Fernando’s server is giving him problem so I am posting it here for everyone to enjoy .
Enterprise Library, System.Configuration and Dependency Injection
What we did
For the new version of EntLib, we did two major changes in the way to deal with configuration and in the way the blocks relate to configuration, as Scott announced a few days ago.
On the configuration side, we switched to the configuration management support provided by .NET Framework 2.0. This has a lot of implications that will be described in later posts, but the most important change is that now all configuration objects extend types from the System.Configuration namespace and its serialization behavior is no longer defined by Xml serialization attributes but by ConfigurationElement attributes. There’s an almost one to one mapping between the configuration support provided by the previous version of EntLib and new the configuration features in the .NET Framework, which makes the transition easier.
As for the relation between the feature objects and configuration, well, there were some major changes. A usual requirement for the previous version of EntLib was to make its features available without having to deal with configuration. One of the main goals for this new version was to make it possible to just create the feature objects, such as providers or databases, and use them without having to rely on any configuration whatsoever. Once we got that we were able to do very interesting stuff with Dependency Injection, as we will see later. For an introduction to Dependency Injection (DI) you can check out http://www.martinfowler.com/articles/injection.html.
Back to basics
We went back to the basics when analyzing how to simplify even further the usage patterns for EntLib.
To use a feature object, we need to get a reference to it. Usually, this means creating it or getting an existing reference to a previously created object.
So, what do we need to create an object? We just need to call the adequate constructor with the adequate parameters. Any user of the library should be able to do that.
What if we could have factories do the same? Just new up objects calling the constructors with the required parameters. And better yet, what if we could do it without writing specific factory code for each object? Well, that's what DI is all about.
Synergy between System.Configuration and DI
Our solution, which will be available on the first preview of this new version, is to make our Configuration objects collaborate with the factories in a generic way, so that the factories can get the appropriate parameters and call the right constructor on the feature objects without us having to write custom code for that.
The key for our solution to work is to annotate the configuration elements with what we call "InjectionParameter" attributes. These attributes let the factories know which constructor to use and how to acquire the parameters to call that constructor. This way, we only need a small injection engine that can interpret the attributes and fire the appropriate constructor lookup and parameter retrieval.
Even better, the configuration objects are not constrained to be ConfigurationElements in the System.Configuration sense for the factories to work well with them. The only requirement is that they have the adequate attributes for the mechanism to work. And of course, the use of these mechanisms is not limited to EntLib ;)
One very important design guideline we imposed ourselves was that feature objects should be completely unaware of configurations and factories. They should just do their job, as long as they were adequately constructed.
The first concept we define is the abstraction of "Factories", which are an evolution of what we already had in the previous version of EntLib. These abstractions are not coupled with the injection mechanism; they just define an API to create objects, whether using DI to do so or not. They are, however, used by the DI mechanism to get objects when required, as we'll see later.
There are some different ways to ask a factory for an object:
A concept that surfaces here is that of "configuration source". It's very similar to the previous version’s ConfigurationContext, but the implementation differs. This will be explained in a later post.
Injection attributes & configuration decoration
Injection attributes are the way to indicate, in a configuration object, what constructor to use and how to get the parameters to call that constructor when creating the feature object described by the configuration object. There are several predefined injection attributes covering all the cases we came across, but the concept is extensible to suit whatever needs surface in the future. Again the concept is simple: provide an argument to a constructor. These are class attributes, used to annotate the configuration types.
This is how it looks:
[InjectionAttributeA(0, typeof(SomeType1), [extra argument parameters])]
[InjectionAttributeB(1, typeof(SomeType2), [extra argument parameters])]
[InjectionAttributeC(2, typeof(SomeType3), [extra argument parameters])]
public class MyObjectConfiguration
The first attribute parameter is the position of the constructor argument defined by it. Of course, these have to be consecutive and non-repeating, zero starting ints. The second attribute parameter is the declared type of the constructor argument. The rest of the parameters depend on the actual injection attribute.
This specification will match to a constructor like:
public class MyObject()
public MyObject(SomeType1 arg1, SomeType2 arg2, SomeType3 arg3)
(There’s no need for names to match in any way, it's just a naming convention).
Usually the arguments for the constructor will depend on the value of a property on the configuration object; however, some times they don't. That's the reason for the first classification for injection attributes: the ones that are related to properties in the configuration object and the ones that are not.
Since the property related injection attributes are by far the most common, we'll focus on them. All of them share an attribute parameter that specifies the name of the property they should deal with.
There are several interesting ways to deal with the properties of the configuration objects, and each has an injection attribute that represents that usage:
The interesting implementations of the factory interfaces are the ones that actually use the injection attributes to do the work for us. In fact, these implementations are built using .NET 2.0 generics, so this gives us a very convenient mix of abstraction and type safety.
The basic implementation of these generic injection factories is:
This is the default implementation, and will usually be enough for most of the factories. Concrete factories that support named object access must override the configuration lookup method; this usually involves just getting some configuration object from the configuration source, but it might be more involved in some cases.
After all this, how do we get to the actual objects? We have several options.
We can ask the factory for the object with a given name:
MyObject object = myObjectFactory.Create(“myObjectName”);
We can ask the factory to create the object with a given configuration:
MyObjectData data = new MyObjectData();
data.PropertyA = XXX;
data.PropertyB = YYY;
MyObject object = myObjectFactory.Create(data);
Or we can just new up the object the old fashioned way:
MyObject object = new MyObject(XXX, YYY, ...);
Once we have the object, we can make it work for us just like we did before.
This was just a glimpse of what will be available in the EntLib CTP. Later posts from the EntLib dev team will address:
· In depth explanations of the DI support: how it works, what will be available out of the box and what can be extended
· The way System.Configuration is leveraged, what was extended and what types were created to make things even easier
· End to end samples to show these mechanisms, both with blocks’ code samples and with completely new implementations.
Now playing: Metallica - The Frayed Ends of Sanity