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!