h1

Dynamic instantiation using reflection

October 1, 2007

I’ll first introduce you to a problem we recently had that required the dynamic provision of a class for a particular task and then discuss how we came to solve it using the reflection method Assembly.CreateInstance().

The background
We have many websites – well into double figures – that all utilise a common exception monitoring HttpModule that we wrote. This module is very pluggable and can also be used by third party sites that we either host or assist with developing.

The ExceptionModule, on a basic level does the following:

  • In the Init() method subscribes to the HttpApplication.Error event
  • Once the error is caught, logs the exception details (in database, event log, xml file depending on setting)
  • Looks to transfer the request to a “landing page”- obtained from web.config setting

This landing page reports a branded apology to the end user for browsers and changes the HttpResponse header so that an appropriate Http Header is sent to the client.

Note: this navigation was done using Server.Transfer() so as not to redirect the browser in any way – it receives a branded page and Http Response for the original request (if you need more information on this, let me know and I can blog in detail about it).

The design problem
The original coding of this module was fine and the application worked as intended. However, soon after being rolled out on many sites we came across a design problem when implementing in one particular site caused by how it was set up.

The site is “split” into two distinct halves of functionality – when there is an error in one half, the exception module needs to transfer to one particular branded “landing” page; if an error occurs on the other half, the module needs to transfer to a different page.

In our original design, this wasn’t accounted for and the landing page was obtained from a name/value pair in the web.config file:
<add key=”HttpLandingPage” value=”landing.aspx” />

The challenges

  • How can we instead have two different parameters for this transfer mechanism?
  • How can the exception monitor/module be sure of the logic of the decision in which “half” of that site it needs to transfer to? It definitely should not sit in this shared utility.
  • If we make it database driven, how do we introduce business logic based on the site location?
  • Have rules without hardcoding them in mother-of-all class with logic based on which site it is in? (e.g. a switch statement where each “case x:” is the site)

Our solution was to enable the site itself to suggest where the landing page should be and be able to decide on the business logic – by providing the ability to customise this whole process, we can make this dynamic.
So how did we do this?

The web.config setting
We changed the web.config setting so that it now provides the assembly name and the class/type that will provide the landing page information (namespace and assembly below is false!):

<add key=”LandingPageProvider”
value=”Biscuit.Landing.GenericLandingPageProvider, BiscuitClasses” />

The ILandingProvider interface
We then defined a simple Interface that classes could implement to provide the landing information to the module code:

public interface ILandingPageProvider
{
   string GetLandingPage(HttpContext context);
}

We also created a generic provider for use in most situations:

public class GenericLandingPageProvider : ILandingPageProvider
{
   public GenericLandingPageProvider()
   {	//no constructor required   }

      public string GetLandingPage(HttpContext context)
   {
      return "landing.aspx";
   }
}

Dynamic Instantiation
The climax of this solution is how we instantiate this string that is in the web.config file and implement this on the fly.
To do this we created a utility class that reads the web.config (using custom ConfigItems not explored here) and creates an instance of the object at run-time:

public class LandingPageUtility
{
   private LandingPageUtility()
   {  // no constructor required - private so cannot instantiate   }

   public static ILandingPageProvider GetLandingPageProvider()
   {
      ILandingPageProvider provider = null;

      string configProvider = ConfigItems.Get("LandingPageProvider");

      if(configProvider.IndexOf(",")>0)
      {
         // Retrieve the assembly and class
         string assemblyName = configProvider.Substring( _
                                 configProvider.IndexOf(",")+1).Trim();
         string className = configProvider.Substring( _
                                 0, configProvider.IndexOf(",")).Trim();

         // create an instance of the class from the assembly
         System.Reflection.Assembly assembly = _
                              System.Reflection.Assembly.Load(assemblyName);
         object o = assembly.CreateInstance(className);

         // check if this class implements ILandingPageProvider interface
         if(o is ILandingPageProvider)
             provider = (ILandingPageProvider)o;
      }

      return provider;
   }
}

The most important parts in the code above are the two lines in the centre of the if statement – we first load the assembly from the web.config setting giving us an instantiated Assembly object and then call the Assembly.CreateInstance() method upon it.
This reflection method uses the System.Activator class to instantiate the type specified by string provided and enables us to achieve our dynamic instantation from the web.config file.
We receive an instantiated object type and then check for the interface implementation before casting.
(Note: this procedure purposefully returns null if the config is set up incorrectly as we know it is specifically consumed by the exception monitor that will already be in the process of handling an exception, so we do not throw another.)

Using the provider
The HttpModule pulls all of this together when it wants to call the Server.Transfer() method.
To retrieve the landing page it does the following:

ILandingPageProvider provider = LandingPageUtility.GetLandingPageProvider();

context.Server.Transfer(provider.GetLandingStaticPage(context) );

In summary
We have enabled the dynamic provision of a landing page and expanded our original design past the limiting one-page provider scenario.
This may (to some) seem like overkill for what is effectively one string, but we have in fact only created one interface, a generic provider class and utility class to instantiate the web.config setting.

What we have done though is enable business logic to be provided on a site-by-site basis – by creating a new class that implements the ILandingPageProvider class we can have simple or complicated code that decides on where the exception module transfer mechanism goes to. We have also future-proofed this for third-party partners who may have more complicated requirements such as our “split” site.

Our solution in the “split” site itself was then to create a custom class that used the HttpContext object that was passed in to retrieve the Request.Url and apply certain rules to decide which page to provide as the landing page.

Advertisements

One comment

  1. […] what class to use to process this feed at run-time (utilising dynamic instantiation using reflection) […]



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: