elsewhere home of a .NET geek

  Home  |   Contact  |   Syndication    |   Login
  21 Posts | 1 Stories | 52 Comments | 35 Trackbacks

News

This blog has random information about Managed Code and Design Pattern. Every day, while i code, the thoughts come in mind are the one you would be reading here.

If you're seeking me for asking any questions, please use the contact page of this site.

Twitter












Article Categories

Archives

Post Categories

One of a requirement given to me recently was tricky. I really amazed after providing solution for the requirement. Thanks .NET you made my life easier :)

It is a ASP.NET application developed in .NET 2.x. The deal is user will configure certain parts of whole class libraries in application configurtion file. For instance, user would say, "I want to use exception management block by using X assembly instead of Y assembly", he will just change few entries in configuration file the entire application funtionality may change. Let me more precise, If suppose the application already has exception management block which will report the application admin with a mail when ever an error occured. But, if user wants to add one more functionality with the existing code of Exception Management Block he would probably add one more class and put it up there, which will implement certain interfaces to comply with the existing Exception Management Block. But, he may also do this in different assembly that uses the interfaces that are implemented in EMB.

Now, the application has to load the assemblies dynamically based on the user configuration, he may say "Use only the assembly that can able to report me as a mail" or he may say "Use only the assembly that can able to report me as a windows event log". It seems to be a meaningful requirement one hard guy can ask, but it was amazingly simpler to implement in .NET by emiting code and loading the assembly dynamically at runtime

I would like to mention the steps here before going much deeper,

  1. First, construct an interface in which you should keep all the public operations that any implementer class would need
  2. Then, create the implementer class constructed using the interface (Perhaps, you can have any number of classes like this)
  3. Configure the web.config file with the type, assembly names (this entries will be used just to read and load assemblies in runtime.
  4. Use AppDomain.CurrentDomain.CreateInstanceAndUnwrap to load the assemblies on-demand

The function CreateInstanceAndUnwrap takes type and assembly name and loads the assembly by using Reflection techniques. Since, the interface can act as a container for the Instanced assembly, you can use all the public operations (and members) where ever required by calling the interface instance itself. Cool right?

You might have a question this time, you can ask where these are mostly required. I can tell you, this can change the way how you code, This approach is something like Plugin architecture, where any routines are plugable in its nature, so any of the software components can be developed and attached without modifying the core parts of the code.

Before getting into much deeper, I would like to tell you about certain conditions where you might need dynamic assembly loading. The following are my examples, and please remember that some of them might be straight forward and some of them might have some other way to easily solve the problem. Here, my objective is to make understand the full usage of the Dynamic Assembly Loading rather than finding out more accurate examples (I guess, some are really accurate examples).

  • When your customer says, "Hey!!, I want to configure the way how this exception is handled in this application, I would like to configure the exception handling methods (what ever it is) that has entirerly different functionalities rather than the one that you provide with your application. Right now, you store all the exception logs into an file, but tomorrow i want it instantly sent to my email-id".
  • When your developer says, "I just want to have radio buttons, instead of check box list .. as i can't do something with this control, let me have the business layer that can help me in defining the UI layer as per my wish".
  • When your customer says, "Hey!!, This is good that you gave me a windows application, but tomorrow i want this samething to be in my existing (or new) web application. Can you do something on this, that cuts my development cost?, Can i have the samething on the web, without bothering much?" -- (this is really a nice question, that i heard)

All this requirements are seems to be nice and seems to be possible right?

Now, lets jump into some code. The example case would be the first one, we will have one interface called IExceptionPublisher which has the public members of how a exception management block could be defined,

interface IExceptionPublisher

{

    void Publish(Exception occuredException, NameValueCollection additionalProps);

}

The Publish(Exception occuredException, NameValueCollection additionalProps) method will be implemented in implementer classes with their own nature, say one implementer class has functionalityof sending the exceptions as a mail, one has other way to do the same etc. For example sake, I have kept two parameters you can add more information about the error and can be published.

Now, we will be having two exception management classes that can be used to report the error

The below class is responsible for sending errors information to the specified file (just a partial implementation)

public class LogExceptionPublisher : IExceptionPublisher

{

    public void Publish(Exception occuredException, NameValueCollection additionalProps)

    {

 

        StringBuilder _errorString = new StringBuilder();

        Exception _excep = occuredException;

 

        // 1. Implementation to dig thru the occuredException and adding the

        //    additional information from the NameValueCollection objects.

        while(_excep != null)

        {

            _errorString.Append(String.Format("Exception:{0}\r\n", _excep.ToString()));

            _errorString.Append(String.Format("StackTrace:{0}\r\n", _excep.StackTrace.ToString()));

            _errorString.Append("-------------------------------------------------");

            _excep = _excep.InnerException;

 

        }

 

        // 2. Read the filename etc., from the Configuration file.

        // 3. Log the information in the specified file.

    }

}

You can see, how it is implemented. But I skipped partial implementation since my scope ends only in explaining the concept. The class has only one method called Publish which will be used to publish the errors.

This class just publishes the exception in the console (Just a partial implementation)

public class ConsoleExceptionPublisher : IExceptionPublisher

{

    public void Publish(Exception occuredException, NameValueCollection additionalProps)

    {

 

        StringBuilder _errorString = new StringBuilder();

        StringBuilder _propsString = new StringBuilder();

        Exception _excep = occuredException;

 

        // 1. Implementation to dig thru the occuredException and adding the

        //    additional information from the NameValueCollection objects.

        while(_excep != null)

        {

            _errorString.Append(String.Format("Exception:{0}\r\n", _excep.ToString()));

            _errorString.Append(String.Format("StackTrace:{0}\r\n", _excep.StackTrace.ToString()));

            _errorString.Append("-------------------------------------------------");

            _excep = _excep.InnerException;

 

        }

 

        for(int i=0;i

            _propsString.Append(String.Format ( "{0}: {1}", additionalProps.GetKey(i), additionalProps[i]));

 

        // Print it in the console

        Console.WriteLine(_errorString.ToString());

        Console.WriteLine(_propsString.ToString());

 

    }

}

Now we have two classes that publishes the exception in different manner, one producing the exceptions into File and other produces the exceptions into Console. The next step is to configure it in the applications configuration file (even it can be any file like xml, flat file etc. The below is a excerpt taken from the Web.Config file.

   

   

The configuration block has type, assembly and enabled attributes for providing information to the EMB classes that implements the IExceptionPublisher interface. For example sake i've used Enabled attribute for one publisher in "No" mode. Now are are ready with all the weapons to start main entry class which calls the Publisher classes based on the configuration setting.

The below class MainPublisher would be responsible of loading the publisher classes on-demand. It also has sample implementation in Main method to show you how to use this classes,

public class MainPublisher

{

    public static void PublishException(Exception error, NameValueCollection _props)

    {

 

        //Read the config file and load all the settings in

        //a serialized object.

        //...//

        //For example, i am using "config" object has the xml data.

 

        foreach(Publisher _publisher in config.Publishers)

        {

            // Check whether publisher is enabled state, otherwise skip

            if(_publisher.Enabled.Equals(PublisherMode.Yes))

            {

                // Load the assembly in to the interface by using the assembly name and type name.

                IExceptionPublisher _publisher = (IExceptionPublisher)

                    AppDomain.CurrentDomain.CreateInstanceAndUnwrap(_publisher.AssemblyName, _publisher.TypeName);

                //Publish the error with currently loaded publisher

                _publisher.Publish(error,null);

            }

        }

 

    }

 

    public static void Main(String argv[])

    {

 

        try

        {

            //Raise an exception

            Int32 a = Int32.Parse("BlahL");   

        }

        catch(Exception error)

        {

            // Just add few more information about the error

            NameValueCollection _nv = new NameValueCollection();

            _nv.Add("Error in: ", "Main method");

            _nv.Add("Cause: ", "While parsing the string to int in Int32.Parse(..)");

 

            // Publish the exception

            MainPublisher.PublishException(error,_nv);

        }

 

    }

}

I guess the code is more self-explainatory and easy to understand. The part in the code is to instantiate and unwrap the assembly to the interface. Since, the interface acts as a lightweight object it will hold the current instantiated class. This is one of the possible to make your software components configurable by the user to change the entire functionalities but limited to the interface.

Hope this article helps you in someway. Let me know your views about this approach, i often try to use in the applications

posted on Saturday, February 25, 2006 8:25 AM

Feedback

# re: An article for understanding CreateInstanceAndUnwrap for loading the assemblies dynamically on runtime 2/25/2006 7:46 PM Steve
One other API to look at along the same lines -- Activator.CreateInstance( Type t );

That's a lighter-weight way of dynamically instantiating objects in the current AppDomain.

AppDomain.CreateInstanceAndUnwrap() is usually used for instantiating types in other AppDomains and then marshalling a reference back to the current AppDomain for remote use.

# re: An article for understanding CreateInstanceAndUnwrap for loading the assemblies dynamically on runtime 12/12/2006 10:46 AM Pavan
object obj = AppDomain.CurrentDomain.CreateInstanceAndUnwrap("MyDLL.dll", "MyDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");

please go through the above code and i am getting below error when run this :
Could not load file or assembly 'MyDLL.dll' or one of its dependencies. The system cannot find the file specified.

Provided: MyDLL is present when the application is running.

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: