The second part of the discussion is opening with a discussion of custom provider development. This is of great interest to me as my recent work with the Model View Presenter pattern has caused me to research and implement dependency injection for many of the layers of my application. The current product that I’m working on is implementing the MVP pattern and is using dependency injection to dynamically load a data layer at run time. There is a need within the product to use a different data access layer assembly for the administrative tools than for the public side of the application. The murky details behind this decision (which I shall leave aside) are to do with the deployment environment and maintenance cycles of the applications going forward. There are a few mechanisms for achieving this dynamic load, however I’ve yet to find conclusive evidence that one method is preferable.
The idea behind dependency injection is improve the following fairly typical line of code:
MyClass myClass = new MyClass();
One potential drawback in this line is that the physical class MyClass has been hard-coded as the only implementation that can exist for myClass. If MyClass implements an interface IMyClass then it might be desirable in the code to switch out the implementation of the interface IMyClass that is being used. The example du jour is switching out an MS SQL data access library for an Oracle data access library. In that example, both implement the same interface but the application wishes to decide which library to use at runtime via a configuration setting. This is a common problem in applications that wish to implement several version of a library than perform very similar but ultimately different tasks. The provider model is based around this need.
The suggested methodology presented in this talk is to use:
Type myType = Type.GetType(“MyNamespace.MyClassName”);
IMyClass myClass = System.Activator.CreateInstance(myType);
The theory here is that Type.GetType returns an object that describes the type to be created. The System.Activator.CreateInstance line creates a concrete instance of the requested class except by this mechanism the class has been created using a string name versus a hard-coded class name. This methodology works for classes that exist within the same assembly, however will not work for classes that exist outside of this assembly. There is an extension to this will work for classes outside of this assembly.
Dynamically Loading Assemblies
In order to extend this methodology to work for classes that are in other assemblies, there is a need to first load that assembly. This is achieved via the following methodology:
Assembly asm = Assembly.LoadFile(MyAssemblyFileName);
IMyClass myClass = asm.CreateInstance(MyClassName);
The basic change here is that now the concrete class instance is created from the assembly reference versus System.Activator. This allows the dyanamically loaded class to reside in a separate assembly. Now we have the ability to specify which data access layer library is being used within the application at run-time. All calls within the application are made against the IMyClass interface, but the implementations now differ based upon the physical data access library that is loaded at run-time.
Finally, interfaces are isolated into a separate assembly from either (any) of the concrete implementations of that interface. The reason for this is that we do not want to require a reference from the main application to either of the implementations of the interface. Such a reference would defeat the purpose of the exercise as it would again tie the application directly to a particular implementation. Instead the main application references only the assembly that contains the interface. Now any implementation of that interface can be used from within the main application by dynamically instantiating the implementation using the mechanism above.