Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

MetaContainer - an abstraction over the dependency injection infrastructure

0.00/5 (No votes)
7 Mar 2009Ms-PL3 min read 20.7K   82  
Description of an abstraction layer over the dependency injection infrastructure

Introduction

Matacontainer enables developers to configure dependency injection infrastructure without being dependent on a particular implementation. Key Metacontainer Use Cases include:

  • Implementing Factory pattern using the ‘child container per factory’ philosophy
  • Integrating existing configuration-and-factory based libraries with dependency injection infrastructure

Design

When designing the Metacontainer, we have decided to define it as an extension to the Common Service Locator[^]. We added the following methods:

  • Register mapping from service to implementation
  • Register mapping from service to implementation creation delegate
  • Create child container

As you can see, there are only three new methods added to the IServiceLocator interface and, by adding these methods, a myriad of new usage scenarios are enabled. By the way, to provide a programmer-friendly interface, we also defined a set of extension methods to the IMetaContainer interface. These additional methods provide type-safe equivalents of base methods by using generic parameters.

The MetaContainer project was started by us, but it is meant to be developed by the community. We have prepared three most commonly used (as we believe) implementations:

These implementations should be treated as reference implementations whose main goal is to show the possibilities of MetaContainer. We encourage all container implementers to provide their own implementations which, we believe, could be tuned better, than our reference product, to a particular container. On the other hand, although designed as a proof-of-concept, implementations provided by us are fully tested and can be safely used in your code, and we will make efforts to provide some support for them.

Factory Pattern

When developing an application using the Inversion of Control paradigm, one can face the necessity of creating a factory object for crating instances of some class hierarchy. In the traditional environment, a factory method is responsible only for choosing which implementation to create in a particular case, based on the arguments provided by the caller. In the Inversion of Control environment, though, there are two additional tasks for a factory class:

  • Injecting dependencies to factory-produced objects
  • Enabling dependency injection infrastructure to inject interceptors into factory-produced objects

Classic solutions of these problems include:

  • Using a main application container to create instances in the factory method. The main disadvantage of this method is the requirement that the factory-produced classes must be known and configured in the app-level container.
  • Creating instances using a simple new operator and then passing the constructed instance to the container for injecting interceptors. Disadvantages of this approach include resolving dependencies of the produced objects at the level of the factory and the necessity of providing abstraction over the injecting interceptors functionality.

The MetaContainer enables us to develop a much better solution. It is based on the ability of the factory to create a child container of the main application container (represented as a IMetaContainer interface) and store it privately. This factory-level container can be filled with mappings specific for the class hierarchy the factory is created for. These mappings are unavailable to external entities, ensuring that no one can depend on particular implementation classes.

Integrating configuration-and-factory based libraries

There are a lot of existing libraries that are based on the pattern of combining XML-based configuration with static factory facades. These factories usually produce instances of classes implementing well-known interfaces which client programmers use to interact with them.

A canonical example of this approach is the Enterprise Library[^] up to version 4.0. Because the way Enterprise Library was designed was an official guidance of the Patterns & Practices group for library architects, many other libraries were implemented the same way.

Our goal in integrating those existing libraries into the dependency injection infrastructure is to enable the container to resolve dependencies on library abstractions. To achieve this, we have to register in the container the mappings of these abstractions to the methods which can create their implementations. These methods, of course, can be based on existing factory functionality built into the library. The MetaContainer lets us do this. All one have to do is to invoke the piece of code which performs the configuration scan and registers all the necessary mappings.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)