November 2009

Volume 24 Number 11

Inside Microsoft patterns & practices - Dependency Injection in Libraries

By Chris Tavares | November 2009

Refactoring Microsoft Enterprise Library

Dependency Injection (DI) is a pattern that has been gaining traction in the .NET developer community over the past few years. Prominent bloggers have been talking about the benefits of DI for quite a while. Several articles on the topic have been published in MSDN Magazine. .NET 4.0 will be shipping some DI-like functionality, with plans to grow it into a full DI system in the future.

In reading the blog posts and articles on DI, I noticed a small but significant bias in the coverage of the topic. The writers talk about using DI in the context of an entire application. But what if you want to write a library or framework that uses DI? How does this change in focus affect the usage of the pattern? This was something that we (the patterns & practices Enterprise Library team) hit head-on a few months ago as we were working on the architecture of Enterprise Library 5.0.

Background

Microsoft Enterprise Library (Entlib) is a very well-known release from the Microsoft patterns & practices group. With more than 2 million downloads to date, it’s used in just about every niche imaginable, from financial institutions and government to restaurants and medical equipment manufacturers. Entlib is, as the name implies, a library that helps a developer address common concerns shared by many enterprise developers. If you aren’t familiar with Entlib, please take a look at our site on the p&p dev center for more information.

Entlib is highly driven by configuration. A large portion of its code is dedicated to reading configuration and assembling object graphs based on that configuration. Entlib objects can get very complex. Most blocks contain lots of optional functionality. In addition, there’s also a lot of underlying infrastructure to support such things as instrumentation, which also needs to get wired up. Because we didn’t want to make our users manually create instrumentation providers, read configuration and so on just to use Entlib, object creation is encapsulated behind factory objects and static façades.

The core of Entlib version 2 through version 4 is a small framework called ObjectBuilder. ObjectBuilder is described by its authors as “a framework for building dependency injection containers.” Enterprise Library is only one of the p&p projects that uses ObjectBuilder; others include the Composite UI Application Block, Smart Client Software Factory and Web Client Software Factory. Entlib in particular took the “framework” part of the description to heart and built a large set of customizations to ObjectBuilder. These customizations provided the functionality needed to read Entlib configuration and assemble object graphs. They were also needed, in many cases, to improve performance over the stock ObjectBuilder implementation.

The disadvantage was that it took quite a while to understand both ObjectBuilder itself (an extremely abstract design plus complete absence of documentation gave ObjectBuilder a deserved reputation for complexity) and the Entlib customizations. As a result, people who wanted to write custom blocks that hooked into Entlib’s object creation strategy were often stymied by the massive learning curve they needed to climb just to get started.

And, to add a further complication, in Entlib 4.0 we released the Unity dependency injection container. With the many advantages of DI, we wanted to make sure that those customers who were, for whatever reason, unable to use one of the many fine open source containers had a good option for DI from Microsoft. And, of course, we wanted to make it easy to get Entlib objects working when using Unity as well. In Entlib 4.0, the Unity integration ended up being a parallel object creation system next to the existing ObjectBuilder infrastructure. Now block writers had to know not only ObjectBuilder and the Entlib extensions, but Unity internals as well, plus some Entlib extensions there. Not a step in the right direction.

Moving Toward Simplicity

We started work on Entlib 5.0 in April of 2009. A major theme for this release was “simplicity for the win.” This included not just simplicity for the end user (the developers calling Entlib) but in the code of Entlib itself. Improvements here would make it easier for us to maintain Entlib going forward, and make it easier to understand, customize and extend for our customers.

One of the major areas that we knew needed work was the object creation pipeline—or should I say pipelines? Maintaining two parallel but different sets of code for the same functionality is a recipe for disaster. Something had to be done.

We set out these goals for the refactoring:

  • Existing client code shouldn’t have to change just because of the architectural changes. Requiring a recompile is OK, but requiring source code changes is not (of course, the client API might change for other reasons). Internal or extensibility APIs are fair game.
  • Remove the redundant object creation pipelines. We should have only one way to create objects, not two (or more).
  • Customers who don’t care about DI shouldn’t be affected by Entlib using it internally.
  • Customers whodo care about DI can choose the container they want to use and get both their objects and Entlib objects out of it.

These goals had quite a few implications, both separately and in combination. The “one object creation pipeline” goal was, on its surface, pretty straightforward. We decided to remove the ObjectBuilder-based system completely and go with a DI container as our object creation engine internally. But then we get to “existing client code shouldn’t change.” The classic Entlib API is a set of static façades and factories. For example, logging a message using the Logging block is done like this:

Logger.Write("My Message");

Under the hood, the Logger façade uses an instance of a LogWriter object to do the actual work. So how does the Logger façade get the LogWriter? LogWriter is a fairly complex class with lots of dependencies, so you can’t just new it up and expect the configuration to be wired appropriately. We came to the conclusion that we needed a global container instance for Logger and all the other static classes in the API. We could just keep a global Unity container, but then we run into “customers get to choose the container they want.”

We want the combination of Unity and Entlib to be a first-class experience. We also want to provide that first class-experience with other containers as well. While the general capabilities of DI containers are common across the board, the way you access those capabilities vary widely. In fact, many builders of containers consider their configuration APIs to be their major competitive advantage. So how do we map our Entlib configuration onto wildly different container APIs?

The Classic Computer Science Solution

It’s a computer science truism: Every problem in computer science can be solved by adding a layer of indirection. And that’s exactly the way we solved our container independence problem. The layer of indirection is what we call a container configurator. At its core, the role of the configurator is to read Entlib’s configuration and configure a container to match.

Unfortunately, reading the configuration itself isn’t enough. Entlib’s configuration file format is very end user focused. You configure logging categories, exception policies, and cache backing stores. It doesn’t say anything about what objects are actually needed to implement that functionality, or what values to pass to constructors or what properties to set. DI container configuration, on the other hand, is all about “map this interface to this type,” “call this constructor” and “set this property.” We needed another layer of indirection that mapped the configuration of a block to the actual required objects to implement that block. The alternative was to have each configurator (you’d need one configurator per container) know about the details of each of the blocks. That is immediately untenable; every change to the code of a block would ripple through all the configurators. And what happens when somebody writes a custom block?

We ended up with a set of objects we’re calling TypeRegistrations. The various configuration sections are responsible for generating a type registration model; a sequence of TypeRegistration objects. The interface for TypeRegistration is shown in Figure 1.

Figure 1 TypeRegistration Class

public class TypeRegistration
    {

        public TypeRegistration(LambdaExpression expression);
        public TypeRegistration(LambdaExpression expression, Type serviceType);

        public Type ImplementationType { get; }
        public NewExpression NewExpressionBody { get; }
        public Type ServiceType { get; private set; }
        public string Name { get; set; }

        public static string DefaultName(Type serviceType);
        public static string DefaultName<TServiceType>();

        public LambdaExpression LambdaExpression { get; private set; }

         public bool IsDefault { get; set; }

         public TypeRegistrationLifetime Lifetime { get; set; }

         public IEnumerable<ParameterValue> ConstructorParameters { get; }

         public IEnumerable<InjectedProperty> InjectedProperties { get; }
    }

There’s a lot here, but the basic structure is pretty simple. This class describes the required configuration for a single type. The ServiceType is the interface that the user will request from the container, while the ImplementationType is the type that actually implements the interface. Name is the name the service should be registered under. Lifetime determines singleton (return the same instance every time) or transient (create a new instance every time) creation behavior. And so on. We chose to use a lambda expression to create the TypeRegistration object because it makes it very easy to specify all this information in a single, compact spot. Here’s an example of creating a type registration from the Data Access block:

yield return new TypeRegistration<Database>(
       () => new SqlDatabase(
           ConnectionString,
           Container.Resolved<IDataInstrumentationProvider>(Name)))
       {
           Name = Name,
           Lifetime = TypeRegistrationLifetime.Transient
       };

This type registration is saying “When requesting a Database named Name, return a new SqlDatabase object, which is constructed with ConnectionString and an IDataInstrumentationProvider.” The nice thing about using the lambda here is that, when writing the blocks, we could build these expressions just as if we were newing up the objects directly. The compiler will type check the expression, so we won’t accidentally try to call a constructor that doesn’t exist. To set properties, you just use the C# object initializer syntax within the lambda expression. The TypeRegistration class takes care of the details of picking through the lambda and extracting the constructor signature, parameters, types and so on so that the configurator author doesn’t have to.

One useful trick we used is that call to “Container.Resolved.” That method doesn’t actually do anything; in fact, its implementation is simply this:

public static T Resolved<T>(string name)
        {
            return default(T);
        }

Why is it there? Remember, this lambda expression is never actually executed. Instead, we walk through the structure of the expression at run time to pull out the registration information. This method is simply a well-known marker. When we find a call to Container.Resolved as a parameter, we interpret that as “resolve this parameter through the container.” We’ve found this marker-method technique to be useful in a variety of places when doing advanced work with expression trees.

In the end, the flow of configuration file to configured container looks like Figure 2.


Figure 2 Container Configuration

One design decision we made is important to explain here. The TypeRegistration system is not, and will never be, a general purpose, configure-everything abstraction for any DI container. It was designed specifically for the needs of the Enterprise Library project. The patterns & practices team is not positioning this as code-based guidance. While the basic idea (extract your configuration into an abstract model) is generally applicable, the specific implementation here is for Entlib only.

Getting Objects out of the Container

So we’ve gotten our container configured. That’s half the battle. But how do you get the objects back out? Container interfaces vary on this as well, although thankfully not as much as their configuration interfaces do.

Luckily, we didn’t have to invent a new abstraction here. Inspired by a blog post from Jeremy Miller in the summer of 2008, the patterns & practices group, the MEF team at Microsoft and the authors of many different DI containers worked together to define a lowest common denominator for resolving objects out of a container. This was published to Codeplex and MSDN as the Common Service Locator project. This interface gave us exactly what we needed; from within Enterprise Library, whenever we needed to get an object out of the container, we could call through this interface and be insulated from the specific container being used. Of course, the next question is: where’s the container?

Enterprise Library doesn’t have any kind of bootstrap requirement. When using the static façades, you don’t need to call an initialization function anywhere. The original library worked by pulling configuration when first needed. We had to replicate this behavior so that the library would be ready to go when called.

What we needed was a standard, well known for getting a properly configured container. The Common Service Locator library actually has one of these: the ServiceLocator.Current static property. We decided not to use this for a couple of reasons. The primary reason was the ServiceLocator.Current could be used by other libraries or even by the application itself. We needed to be able to set the container at first access of any Entlib object; anything else was a recipe for hair loss as people tried to figure out why their carefully constructed containers disappeared, or why Entlib worked on the first call but didn’t afterwards. The second reason has to do with a shortcoming in the interface itself. There’s no way to query the property to find out whether it’s been set. That made it hard to determine when to set up the container.

So, we built our own static property: EnterpriseLibraryContainer.Current. You can set this property from user code as well, but it’s specifically part of Enterprise Library so there’s less chance of conflicts with other libraries or the main application. On the first call to a static façade, you check EnterpriseLibraryContainer.Current. If it’s set, you use whatever is there. If not, you create a UnityContainer object, configure it using a configurator and set it as the value of the Current property.

The result of this is that there are now three different ways to access the functionality of Enterprise Library. If you use the classic API, everything just works. A Unity container under the hood will be created and used. If you’re using a different DI container in your application and don’t want Unity in your process but are still using the classic API, you can configure your container using a configurator, wrap it in an IServiceLocator, stick it in EnterpriseLibraryContainer.Current, and then the façades will continue to work. Only now they're using your container of choice under the hood. We don’t actually supply any container configurators in the main Entlib project other than for Unity; our hope is that the community will implement them for other containers.

A second option is to use EnterpriseLibraryContainer.Current directly. You can call GetInstance<T>() to get any Enterprise Library object and it’ll give you one. And again, you can stick a different container behind it if you want.

Finally, you can simply use your container of choice directly. You’ll have to bootstrap the Entlib configuration into the container using a configurator, but if you’re using a container, you need to set it up regardless, so this isn’t a new requirement. From there, you simply inject the Entlib objects you want as dependencies and you’re off and running.

How’d We Do?

Let’s look back at our set of goals and see how this design stacks up.

  1. Existing client code shouldn’t have to change just because of the architectural changes. Requiring a recompile is ok, but requiring source code changes is not (of course, the client API might change for other reasons). Internal or extensibility APIs are fair game.

    MET. The original API still works unchanged. If you don’t care about dependency injection, you neither need to know nor care about how your objects are wired up under the hood.

  2. Remove the redundant object creation pipelines. We should have only one way to create objects, not two (or more).

    MET. The ObjectBuilder stack is gone from the code base; everything is now built via the TypeRegistration and configurator mechanisms. You do need one configurator per container.

  3. Customers who don’t care about DI shouldn’t be affected by Entlib using it internally.

    MET. DI doesn't present itself unless you want it to.

  4. Customers whodo care about DI can choose the container they want to use and get both their objects and Entlib objects out of it.

    MET. You can either use your DI container of choice directly or you can have it used under the covers behind the static façades.

We ended up with some additional benefits as well. The Entlib code base got simpler. We ended up deleting about 200 classes from the original implementation. After adding the type registration pieces, we were down about 80 classes total after the refactoring was done. Additionally, the classes that were added were simpler than the ones that were removed, and the overall structure was significantly more consistent, with fewer moving parts or special cases.

Another advantage was that the refactored version turned out to be a little faster than the original, with some initial, informal measurements showing a 10 percent performance gain. After we saw the numbers, this actually made sense to us. Much of the complexity in the original code was from a series of performance optimizations that worked around ObjectBuilder’s slow implementation. Most DI containers have had significant work done on their general performance. By rebuilding Entlib on top of a container, we can take advantage of that performance work and not have to do it a lot ourselves. As Unity and other container evolve and are optimized further, Entlib should get faster without a whole lot of effort on our part.

Lessons Learned for Other Libraries

Enterprise Library is a good example of a library that really takes advantage of a dependency injection container without being hard coupled to one. If you’d like to write a library that uses a DI container but doesn’t force your choice on your consumer, we hope you can find some design inspiration from our example. I think our goals for the change, particularly these last two, are relevant to any library author, not just Entlib:

  • Customers who don’t care about DI shouldn’t be affected by Entlib using it internally.
  • Customers whodo care about DI can choose the container they want to use and get both their objects and Entlib objects out of it.

When designing your library, there are several questions you need to think about. Be sure to consider these:

  • How is your library bootstrapped? Do your clients have to do something specific to get your code set up, or do you have a static entry point that should just work?
  • How do you model your object graphs so that a container can be configured without your having to hard-code calls into that container? Take a look at our TypeRegistration system for inspiration.
  • How will the container you’re using be managed? Is it going to be handled internally, or do your callers manage it? How does the caller tell you which container to use?

We came up with a good set of answers to these questions for our project. I hope our example can provide inspiration when you’re designing yours.


Chris Tavares is a developer on the Microsoft patterns & practices team, where he is the dev lead for Enterprise Library and Unity. Prior to Microsoft, he worked in consulting, shrink wrap software and embedded systems.