Wednesday, May 06, 2009

Dependency Injection and StructureMap (1)

Recently I have been working a project with DI and StructureMap. The concept is not new but StructureMap was new for me. I did not take too long for me to understand how to use it, and soon I fall in love with SM.

The application is kine of reading data, processing data and finally writing data. The data are mostly from database such as Microsoft SQL or Oracle db. The processing part is based on business requirement. The destinations of data various from database, text files, emails or reports. There are many process in the same pattern. Then I decided to break the process into three parts as interfaces: IDataReader, IDataProcess and IDataWriter. On top of these three is the manager IProcessController. For different applications, this pattern can be repeated again and again by injecting implementation parts.

I did some research on DI framework. There are many great frameworks available, such as Spring.Net, Castle Project's Windsor Container, and Microsoft's MEF. All of them are open source frameworks. However, I find out that SM is only focused on DI and it does it very well.

I first tried it based on XML configuration. It is really straightforward. However, soon I found out that there is a better way to do it: Registry DSL(domain specific language) to make mapping between interface and class(actually it can also do for class to class). Think the Registry DSL as XML configuration, even it is done in .Net such as C#. Not only this provides a mush secure mapping, but it also provides much powerful ways to achieve DI which would be very hard to do in XML. Since the mapping is done within assembly, I think the performance should be much better than loading XML configuration files. According to SM, Registry DSL is a recommended way to configure DIs.

XML configuration files contains only PluginFamilies and Pugins logic. I also do the DI configuration in a separate assembly library project. My application can only see the interface libraries, domain class libraries, some commonly used libraries such as tools and .Net framework libraries, and the Registry DSL library:



The above is a slide show in my presentation on a demo case. ProcessDemoSM is the SM engine to load DI mappings to SM framework. ProcessDemoSM library sees all the interfaces and the libraries where implementation classes to be mapped. The application does not know the concrete classes. This makes the swap of implementations much easy and simple!

With the xxxSM project, there two basic classes, for example, SMForDemoApp (public class) and SMRegistry (based on Registry and internal class, ie, not visible to the outside of the assembly). Here is the example of SMForDemoApp class:

using StructureMap.Configuration.DSL;
public static class SMForDemoApp
{
private static bool _registered;
private static Configuration _configuration;
public static void InitializePlugins(
string configFile)
{
if (!_registered)
{
// Get configurtion information
_configuration = GetConfigInstance(configFile);
// Create Registry from this assembly
Registry registry = new SMRegistry(_configuration);
ObjectFactory.Initialize(x =>
{
x.AddRegistry(registry);
}
);
}
}

T GetInstance<T>() where T: class
{
T instance = null;
if ( typeof(T) == typeof(IProcessController) )
{
instance = ObjectFactory.GetInstance();
}
return instance;
}
}

The static class contains two private data members. _registered is straightforward. This guaranties SMRegister class is created only once. Within the class, it will load all the DI mappings to SM framework. The second one is a customize Configuration class. The class contains all the application information which are needed for instantiating implementation classes. In this example case, I store the configuration information in a file, eitehr JSON or XML file.

The interface InitializePlugins() is used to load Registry instances to SM framework. Here MSRegistry is derived from Registry class.

The method GetInstance<T>() returns an instance of generic type from SM framework. I make this method as generic so that if you need more than one types of instances, you can use this method.

The SM assembly is only referenced in this project. In my application, I don't need to add SM reference any more. I only need to add reference to this project or library. This library is like a wrapper class. It provides enough interfaces to instantiate DIs mappings to SM framework and method to get required instances back. Normally T type is by interface. A client or user does not what implementation class is mapped to. If you need to do different mapping, the only change is this library. You may think this library as SM's XML mapping file.

Here is an example in my console application, SMForDemoApp.

static main(string[] args)
{
SMForDemoApp.InitializePlugins();
IProcessController controller =
SMForDemoApp.GetInstance<IProcessController>();
controller.Start();
}

The console application is very simple. It gets an instance of IProcessControler and
calls Start() method to start process. The DI mapping is done within SMForDemoApp which relies on SM to load mapping. In the implementation class(IProcessController) uses many interface instances as well. SM will magically create instances for you, and all the instances will be injected to your implementation classes through constructor or property. You would not need to worry about how to create instances and pass instances in your implementation classes. You just concentrate on your implementation business logic.

The next thing I'll talk is about Registry class. SMRegistry class is based on SM's Registry class. In my next blog, I'll continue on the SMRegistry class.

1 comments:

Sunit Joshi said...

Nice post. It would be real helpful if you could post some scenarios using constr args at runtime.