in

ASP.NET Weblogs

brady gaster

yadnb

November 2003 - Posts

  • Team-based Provider Model Goodieness

    This is beginning to get really interesting to me. I didn't really dig the caching mechanism in that last sample. It just seemed kind of squirly, so I sat there staring at it for a little while. Then I received a comment with a really awesome suggestion on how to clean the caching logic up. So I did. Once I got home from work I was really thinking about how to improve on this model, and I notice a second comment from Frans suggesting that I might want to think about a factory pattern.

    Hmm, seems like a really interesting idea indeed.”

    So off I went, creating the new, groovy, PersonHandlerFactory class. This little guy does a lot of the work that the Run() method was doing a little while ago. Type-casting all all sorts of things. The end result of the main method of this class, Create(), is to produce an instance of a Provider class to the caller, either from the cache or by late-binding - only this time, we completely remove the call to Activator.CreateInstance(). Quite interesting indeed - cleaner code, easier to read, and most likely a teensy bit faster than the previous iteration.

    /// <summary>
    /// Hander-outer of IPersonHandler Providers.
    /// </summary>
    public class PersonHandlerFactory
    {
     
    internal PersonHandlerFactory(){}

      /// <summary>
      /// Checks to see if the constructor has been added to the web
      /// server cache and if not, it is simply returned. If the 
      /// ConstructorInfo instance has been added to the web server cache,
      /// it is invoked and the new object is returned.
      /// </summary>
      /// <param name="typeName"></param>
      /// <returns></returns>
      public static IPersonHandler Create(string typeName)
      {
        IPersonHandler provider =
    null;
        if(HttpContext.Current != null)
        {
          Cache cache = HttpContext.Current.Cache;
          // Check the cache for this type to see if we've already got the contructor
          ConstructorInfo constructor = (ConstructorInfo)cache[typeName];
        
          // If we don't already have the constructor, get it now
          if(constructor == null)
          {
            // Get an instance of the specified type
            Type t = Type.GetType(typeName);

            // Get the default/empty constructor
            constructor = t.GetConstructor(new Type[0]);

           // Cache this constructor info for future lookups
           cache.Insert(typeName, constructor);
          }

        // first, get the object from the constructor
        object o = constructor.Invoke(null);

        // convert that puppy!
        provider = o as IPersonHandler;
       }
       return provider;
      }
    }

    Of course, we're going to have to make a slight change to the Engine class's Run() method. This class has now become somewhat of a facade to the work that the factory's doing.

    /// <summary>
    /// Runs the collection of providers on a person instance.
    /// </summary>
    public class PersonEngine
    {
     
    /// we won't allow construction, as the static Run method will be enough.
     
    internal PersonEngine(){}

     
    /// <summary>
     
    /// Executes the collection of providers' functions.
     
    /// </summary>
      public static void Run(Person personInstance)
     
    {
      // get the name of the type of provider we're supposed to use
      string typeName = String.Empty;
      PersonSettings settings = PersonSettings.GetSettings();
      // set up a local variable to reference the person class
      // so we can continue to act on it repetitiously
      Person pTmp = personInstance;
      for(int i=0; i<settings.TypesInProcess.Length; i++)
      {
        typeName = settings.TypesInProcess[i];
        // make sure it's an implementor of the proivider interface
        IPersonHandler handler = PersonHandlerFactory.Create(typeName);

        // perform it's functionality
        pTmp = handler.HandlePerson(pTmp);
        }
      }
    }

    Nice! This project is progressing along rather nicely. Any more suggestions?

  • Benchmarking the Provider Goodieness

    Just to be... well.. anal about the performance benefits of the caching idea, I ran my example ASPX page again, this time writing out the Environment.TickCount for the start and the end of the process. Without caching - that is, using Activator.CreateInstance - the process took 591 milliseconds. With the constructor being cached, I tried 3 results. The first? 20 milliseconds. The second? 0. The third? 10.

    Nifty.

  • More Provider Goodieness

    Thanks to an idea submitted by everyone's buddy Rob Howard, I've slightly extended the idea from yesterday to exemplify his example of loading the types from the cache instead. This post will just touch on the changes needed to implement Rob's suggestion, so if you haven't read yesterday's article on using the Provider Model to provide you with flexible workflow logic, click here.

    Now that you've read that, let's continue.

    As Rob pointed out, creating types can be an expensive process that, can be expedited depending on how it is executed. Rob's point yesterday was that we can store the ConstructorInfo for our Provider class Type into the web server's cache, and then later invoke that constructor directly from the cache to produce a new instance of the type. To augment yesterday's code with this type of functionality, I've added a new method to the Engine class, which basically performs a check to see if the Type's ConstructorInfo has been added to the cache. If it has not, the Type is created in the traditional method using Activator.CreateInstance(). If, however, the typeName is found in the cache, we simply invoke the type's constructor and return whatever we expected back to the Run method's call. Here's the code for the new method, GetProviderFromCache.

    /// <summary>
    ///
    Checks to see if the constructor has been added to the web
    ///
    server cache and if not, it is simply returned. If the
    ///
    ConstructorInfo instance has been added to the web server cache,
    ///
    it is invoked and the new object is returned.
    ///
    </summary>
    ///
    <param name="typeName"></param>
    ///
    <returns></returns>
    static object GetProviderFromCache(string
    typeName)
    {
      object provider = null
    ;
      if(HttpContext.Current != null
    )
      {
        Cache c = HttpContext.Current.Cache;
        if(c[typeName] == null
    )
        {
          // create an instance of that type
          Type t = Type.GetType(typeName);
          c.Insert(typeName,t.GetConstructor(
    new
    Type[0]));
          provider = Activator.CreateInstance(t);
        }
        else
        {
          provider = (((ConstructorInfo)c[typeName]).Invoke(
    null
    ));
        }
      }
      return
    provider;
    }

    And finally, here's the updated Run method, which makes use of this new functionality.

    /// <summary>
    ///
    Executes the collection of providers' functions.
    ///
    </summary>
    public static void
    Run(Person personInstance)
    {
      // get the name of the type of provider we're supposed to use
      string
    typeName = String.Empty;
      PersonSettings settings = PersonSettings.GetSettings();

      // set up a local variable to reference the person class
      // so we can continue to act on it repetitiously
      Person pTmp = personInstance;
      for(int
    i=0; i<settings.TypesInProcess.Length; i++)
      {
        typeName = settings.TypesInProcess[i];
       
        // now create an instance of that type
        object provider = GetProviderFromCache(typeName);

        // make sure it's an implementor of the proivider interface
        IPersonHandler handler = provider as IPersonHandler;
        if(handler != null
    )
        {
          // perform it's functionality
          pTmp = handler.HandlePerson(pTmp);
        }
      }
    }

    Thanks Rob! Awesome idea!

  • Built-in SQL Server Password Hashing

    Not sure how many of you know about this already, but I sure didn't. My nice Russian DBA told me this trick this morning. Apparently there's a built-in SQL Server function called pwdencrypt. It is the function SQL uses internally to encrypt SQL Server users. Anyway, here's a little SQL script you can run in Query Analyzer to see how it works.

    select pwdencrypt('apassword')
    select pwdcompare('apassword',pwdencrypt('apassword'))

    Note - I do not condone the safety or security of this technique. I just found out about it today and thought it was nifty. Feel free to educate your peers in the comments of this post if, for some reason, you know this to be a bad idea.

  • Using the Provider Model to Modify Application Workflow

    With all this talk about the Provider Model, it's importance to Whidbey, and all the nifty things you can do with it from the point of view of enabling a pluggable architecture, and the discussions surrounding the extensibility that it can provide an application, I got to thinking. I noticed that, from all points I've seen regarding the Provider Model, it's sole purpose has been to allow developers the ability of specifying to their applications' innerworkings “use this object in this spot to do this one little thing.”

    While that's all well and good, I began to think to myself, “what about using the Provider Model to not only extend an application at one place, but to change or control the overall pathway through the application?” In a sense, I'm talking about changing the process by which an application functions - changing the workflow via the Provider Model.

    This article will posit such a paradigm and show you, in a step-by-step fashion, just how something like this could be achieved. We'll use the most common example possible - the consumption and use of a generic Person object captured in a web form environment - to exemplify Provider Model as a vehicle for workflow modification. So to begin with, let's state the problem.

    There's this web site I have to create that will capture information about visitors. We'll need to capture their first and last names, and email addresses. Then, we'll want to do something with that information, but we want to allow the architecture room to grow while at the same time not requiring much modification to the underlying architecture. In a sense, the whole logical flow should be driven by, and changed by, the provision of new plug-ins that will perform small pieces of functionality.

    For starters, we'll need a Person class that the web application will use for entity persistence. The code for the Person class is relatively simple. Note in particular that we've specified this class is a serializable class (we'll use that later on in our first Provider class).

    /// <summary>
    ///
    The class we'll operate on.
    ///
    </summary>
    [Serializable()]
    public class
    Person
    {
      public string
    Firstname;
      public string
    Lastname;
      public string
    Email;
    }

    Not too much to look at. Then again, we don't need too much to look at, as this is just an entity object that we'll be operating on. The operatee isn't what's important here but rather the operation that actually happens. To define the basic structure of classes which will actually perform operations on Person objects, we'll create a simple interface called IPersonHandler.

    /// <summary>
    ///
    Interface all providers will inherit from.
    ///
    </summary>
    public interface
    IPersonHandler
    {
       Person HandlePerson(Person personInstance);
    }

    This interface defines the most basic structure of any provider class used by the system. So long as the classes which implement this interface implement the HandlePerson method, the class is golden and should plug right into the architecture with no problem. Notice in particular how the HandlePerson method takes an instance of a Person class and how it also returns an instance of a Person class. We're doing this so that, as we move through the workflow process, each step of the way picks up the previous step's changes to the Person object. In essence, we use the object and pass it along; if one step changes the object, the next step can react to those changes!

    As is true with most Provider Model implementations, we'll need to allow developers a very easy way of snapping plugins in and out of the application's architecture. To solve this problem, we'll create our own custom configuration section reader. This reader will basically look through the web.config file, where the type names will be placed in sequential order. To begin with the discussion of this process, take a look at the code for the PersonConfigurationReader class, which implements the IConfigurationSectionHandler interface.

    public class PersonConfigurationReader : IConfigurationSectionHandler
    {
      public object Create(object
    parent,
       
    object
    context,
        XmlNode section)
        {
           XmlNodeList lstActions = section.SelectNodes("//typeName");
           string[] types = new string
    [lstActions.Count];
           for(int
    i=0; i<lstActions.Count; i++)
           {
             types[i] = lstActions[i].InnerText;
           }
           return new
    PersonSettings(types);
        }
    }

    If you take a look at what's going on here, you'll see that we're basically concerned with the section parameter of this method. Looking carefully at this implementation, you'll notice that we expect this node to contain child nodes named “typeName.” In essence, we're going to take the idea of the Provider Model - allow a developer to specify their own Type to provide their own functionality - and extend it by allowing a developer the ability of daisy-chaining multiple Providers together.

    The last line of code in our Create method implementation returns an instance of a new Type called PersonSettings. This settings class' code can be seen below. Notice especially how we're passing in a string array; we'll eventually return that array via the TypesInProcess property, which will specify the order in which we'll process a Person class instance.

    /// <summary>
    ///
    The settings class, which contains the type name to be loaded.
    ///
    </summary>
    public class
    PersonSettings
    {
      const string
    section = "tatochip.com/Person";
     
      internal
    PersonSettings(string
    [] types)
      {
        TypesInProcess = types;
      }
     
     
    public readonly string[] TypesInProcess;
      
      public
    static
    PersonSettings GetSettings()
      {
        PersonSettings b = (PersonSettings)cs.GetConfig(section);
        return
    b;
      }
    }

    Now that we've created the configuration reader and settings classes, let's get back to the implementation of the IPersonHandler interface. We'll take a look at the custom configuration section in a moment; before we specify some types to create and use during the workflow process, we'll first need to create those types' class structures. For starters, take a look at the simplest of all of these Provider classes, the FileBasedPersonHandler class, which basically just serializes a Person class (hence the provision of the Serializable attribute in the Person class' code earlier) to a file on the hard disk.

    /// <summary>
    ///
    Serializes the class and saves it to disk.
    ///
    </summary>
    public class
    FileBasedPersonHandler : IPersonHandler
    {
      public
    Person HandlePerson(Person personInstance)
      {
        string
    filepath = @"C:\" + personInstance.Firstname + "_" +  personInstance.Lastname + ".xml";

        FileStream fs =
    null
    ;
        fs =
    new
    FileStream(filepath,FileMode.Create);

        SoapFormatter soap =
    new
    SoapFormatter();
        soap.Serialize(fs,personInstance);
        fs.Close();
       
       
    return personInstance;
      }
    }

    Not too fancy, but it does a good job of explaining one possible scenario; we'll save each person object to disk for persistence.

    So what if that's not good enough? What if we also want to save each Person to a database somewhere? Not to worry, we just create a new Provider class and give it whatever implementation we desire. In the DatabasePersonHandler Provider class, we just execute a stored procedure in a database and save the Person to SQL Server.

    /// <summary>
    ///
    Saves the person to the database.
    ///
    </summary>
    public class
    DatabasePersonHandler : IPersonHandler
    {
      public
    Person HandlePerson(Person personInstance)
      {
        SqlConnection cn = 
        new
    SqlConnection("Data Source=HRDB; User Id=DBuser; Password=pass4dbUser; Initial Catalog=PersonDB");
        SqlCommand cmd =
    new
    SqlCommand("uspInsertPerson",cn);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add("@firstName",personInstance.Firstname);
        cmd.Parameters.Add("@lastname",personInstance.Lastname);
        cmd.Parameters.Add("@email",personInstance.Email);
        if
    (cn.State != ConnectionState.Open) cn.Open();
        cmd.ExecuteNonQuery();
        if
    (cn.State != ConnectionState.Closed) cn.Close();
        return
    personInstance;
      }
    }

    Now that we've succesfully provided the application the ability of saving each Person our web site receives to file and/or to a database, we'll add one final piece of functionality - marketing! The EmailPersonHandler Provider class will basically shoot an email to the visitor informing them that their account was created, and that we appreciate their business.

    /// <summary>
    ///
    Notifies the person that they're accomodated.
    ///
    </summary>
    public class
    EmailPersonHandler : IPersonHandler
    {
      public
    Person HandlePerson(Person personInstance)
      {
        MailMessage msg =
    new
    MailMessage();
        msg.Subject = "Person Instance Handled";
        msg.Body = personInstance.Firstname + " " + personInstance.Lastname + " was handled succesfully. Thanks for submitting yourself!";
        msg.To = personInstance.Email;
        msg.From =
    “noreply@site.com“;
        SmtpMail.SmtpServer = "smtp.myserver.com";
        SmtpMail.Send(msg);
        return personInstance;
      }
    }

    So, we've almost done it. We've created a custom configuration reader, a settings class which informs us about all the types we've got in our process model, and we've created a few Provider classes to start up our own process. The next step is to basically kick the process into gear. We'll do this by creating an Engine class.

    The PersonEngine class below does the work for us; it reads in the custom configuration settings, then creates an instance of each type specified in the custom configuration settings, and executes that type's functionality on the Person instance provided to it. Each step of the process persists the Person instance to the next step. Though none of these Provider classes actually make any changes to the Person instance passed in, you most likely get the point (and a few ideas of your own, hopefully!). Take a look at this class, most importantly the Run method, which kicks the whole process off.

    /// <summary>
    ///
    Runs the collection of providers on a person instance.
    ///
    </summary>
    public class
    PersonEngine
    {
      /// we won't allow construction, as the static Run method will be enough.

      internal PersonEngine(){}

      ///
    <summary>
      ///
    Executes the collection of providers' functions.
      ///
    </summary>
      public static void
    Run(Person personInstance)
      {
        // get the name of the type of provider we're supposed to use
        string
    typeName = String.Empty;
        PersonSettings settings = PersonSettings.GetSettings();
       
        // set up a local variable to reference the person class
        // so we can continue to act on it repetitiously
        Person pTmp = personInstance;
        for(int
    i=0; i<settings.TypesInProcess.Length; i++)
        {
          typeName = settings.TypesInProcess[i];
          // create an instance of that type
          Type t = Type.GetType(typeName);

          // now create an instance of that type
          object provider = null
    ;
          provider = Activator.CreateInstance(t);

          // make sure it's an implementor of the proivider interface
          IPersonHandler handler = provider as
    IPersonHandler;
          if(handler != null
    )
          {
            // perform it's functionality
            pTmp = handler.HandlePerson(pTmp);
          }
        }
      }
    }

    Now that we've got the vehicle and Provider classes set up, let's take a look at the custom configuration section. First off, we'll need to inform the configuration reading process that “we've got a custom section in here,” and that, in order to know what to do with that section, you'll need to make use of our new custom configuration reader class (the PersonConfigurationReader class from earlier). The first snippet of the web.config code can be seen below.

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>
       
    <configSections
    >
          <sectionGroup name
    ="tatochip.com">
          <section

            name="Person"

            type
    ="ProviderWorkflow.PersonConfigurationReader, TestSite"
          />
        </sectionGroup
    >
      </
    configSections>

    Now that we've informed the runtime that we've got this custom section enclosed later on in a node called “tatochip.com,” and you'll need to use the ProviderWorkflow.PersonConfigurationReader class to know what to do with it. Finally, take a look at that code below, which specifies a complete list of providers to drive the workflow of the application.

      <tatochip.com>
        <Person
    >
          <actionList
    >
            <typeName>ProviderWorkflow.FileBasedPersonHandler</typeName
    >
            <typeName>ProviderWorkflow.EmailPersonHandler</typeName
    >
            <typeName>ProviderWorkflow.DatabasePersonHandler</typeName
    >
          </actionList
    >
         </Person
    >
      </
    tatochip.com
    >
    </configuration>

    Now, we create a very simple ASPX page that captures the data from a web visitor using a few texboxes, and kick off the whole process when the user clicks a submit button.

    private void btnSavePerson_Click(object sender, System.EventArgs e)
    {
      // first build the person according to what was provided from the user
      Person p = new
    Person();

      p.Firstname = txtFirst.Text;
      p.Lastname = txtLast.Text;
      p.Email = txtEmail.Text;

      // now process it
      PersonEngine.Run(p);

      // display confirmation
      lblConfirm.Text = "The process has completed.";
    }

    When the form is submitted, each of the Provider classes specified in the web.config's custom configuration section will be instantiated and the interface implementation residing in each executed. The result? Dynamic functionality that can be altered without the requirement of code modification or recompilation. In essence, we've provided any developer who inherits this application the easiest possible mechanism for extension or expansion. They simply need to implement our IPersonHandler interface, and specify at what stage in the workflow process their own implementation will occur.

    Voila! Workflow via the Provider Model!

  • the student becomes the teacher

    So, Robert has once again posited an idea that, for some reason or another, hasn't recahed the mark with many. Go look at the comments if you don't believe me on this one, as they're all either (A) slamming Robert (as in, asking for a Robert-less main feed) or (B) totally missing the point of Robert's whole discussion.

    First of all, i'm going to do what Robert never does - openly name names. Robert rocks. Do you remember when you were a kid on the playground and you were picked on by a bully? And remember how when you told your mom about it, she said “don't worry, they're just jealous.” We can see this pattern evolving all around us. Just look at how much Sun Microsystems and IBM loathe Mr. Gates and Microsoft. Why? Because they're jealous.

    So here it is, for all the naysayers out there who continually bash Robert. You, my colleagues, are simply jealous of him. Because he has an MVP and you don't. Because he has his own company and you don't. Because he's writing software in his way and you aren't. Because he's doing it all - every single step of the way - his way. And, because he's doing it all at the ripe young age of pre-25.

    And that jealousy, my colleagues, is why he is continually bashed by everyone. He is producing.

    So for starters, let me say this - take notice of him and listen to what he has to say. Don't bash him because he talks a lot. He has good things to say, and if you'd all listen, you might pick up on that fact.

    Now, on the article. Sure, he may be marketing his product in some roundabout way. If you had a product, wouldn't you market it? Now that that's outta the way, i'll continue (now that you bashers have realized you'd do the same thing if you were in his shoes).

    His article posits a wonderful idea - make it easy for even the most skilled users to facilitate. Make it simple. Make it small, and make sure its flexible. Bang it out in such a way that it can be used by anyone easily, that it can be extended by anyone using proven techniques, and make sure you get it out there. Robert has an awesome, awesome idea. His essay is something we should all take notice of. It posits a wonderful series of methodologies - make sure it's easy, make sure it does what it does as well as can be, and never quit making it easier to use, no matter how totally wacky the internal architecture has to be to make that a reality.

    i wish all developers could be like this, could share this vision. .NET has made it really easy for us to help one another out via reusable code, and Robert is a shining example of how one developer - or one good leader - can use .NET to make tools that make developers' lives easier. His vision, his motiviation, and his courage to do it his own way make him a shining example of what we should all be -

    Energetic developers who keep pushing our own limitations to make our colleagues' lives easier.

  • delvegraphics.com

    DelveGraphics have redesigned their site. well, "they" is really a "he," and he is an awesome friend of mine named dave who's even a more awesome designer. and father. and guitarist. and dj. and pretty much everything else he does. he's just one of those amazing people who does everything pretty stinking well.
  • A new book on Smart Clients

    So, i'm accepting an offer to assist a team of authors in the writing of a new book by Addison-Wesley. This should be a pretty interesting project, as it's main focus will be on the development of .NET Smart Clients. Thing is, i'm trying to gather some resources right now, as we're in the planning stages of the book. So i'm wide open at the moment, trying to locate as many documents and links as possible on the topic. So if you've got some, hook a brotha up!
  • Is there an organized North Carolina user group?

    Here we go, rant #1 while a North Carolina native. Let's hope i burn no bridges.

    It seems that the user group situation in North Carolina is uninvolved at best. First of all, there's the Enterprise Developer's Guild. Sure, they meet at the Microsoft campus. Their web site is uninformative. I've emailed every single person listed as a contact at least twice, and i've not yet heard back from anyone. i emailed once to find out about a mailing list (as the only one i saw that was “useable” bombed when i entered my email address to sign up), another time to offer my services as a trainer and/or speaker. This whole process, coupled with the fact that there appears to be no formal mailing list at all leaves me a little, well, frustrated. Granted - i have not yet had the time to attend any of the meetings, so i have no idea the caliber of the group. Yet, if i have to take time out of my schedule to remember to go to the web site to look up the next meeting, what's the point? Developers are busy people, and forgetful at times, too. They need to be prodded when these meetings happen. Additionally, i've heard that this group isn't 100% dedicated to .NET. Like i said, i'm not sure of this, but if it is true, there's a problem.

    Second is the Piedmont Triad User Group, which serves the central portion of the state. So for meetings, it's not very useful. Still, there seems to be no formalized mailing list. Which is, of course, a little disenchanting. The AZDNUG  mailing list was so helpful to so many people, why don't either of these groups have one going on?

    So there's my rant. i think that the AZDNUG group and list is about the most perfect example of a productive list which helps people learn about .NET. Good speakers, Microsoft involvement, and lots of stuff to give away at every meeting. The members were there to help one another out, and lots of code got shared each month. i'd like to see something in North Carolina like this.

    Better yet, i'd like to either start something like this - a user group and mailing list dedicated solely to .NET Developers - or help out with one of the current initiatives going on. So if anyone's interested, or if anyone knows something i don't about one of these groups, please - shout about it!

  • Awesome OReilly Reflection Article

    And written by a fellow Charlotte native, at that! And, which mentions attributes that mark code with requirements! That was the idea i was working on! But, i won't complain, this article does an awesome job at pointing out still even more uses for reflection. Excellent!
More Posts Next page »