다음을 통해 공유


3 - Dependency Injection with Unity

patterns & practices Developer Center

On this page: Download:
Introduction | The Dependency Injection Lifecycle: Register, Resolve, Dispose | Register | Resolve | Dispose | Registering and Resolving in your Code | Adding Unity to Your Application | A Real-World Example | Type Registrations in the Example - Instance Registration, Simple Type Registration, Constructor Injection, Registering Open Generics, Parameter Overrides | Resolving Types in the Example - Simple Resolve, Resolving in an MVC Application, Using the Per Request Lifetime Manager in MVC and WebAPI Application, Resolving with Run Time Information | Registration | Named Type Registrations | Design-Time Configuration | Registration by Convention | Registration by Convention and Generic Types | Using Child Containers | Viewing Registration Information | Resolving | Resolving in an ASP.NET Web Application | Resolving in a WCF Service - Using the UnityServiceHost Class with a Self-hosted Service, Using the UnityServiceHost Class with Service Hosted in IIS or WAS | Automatic Factories | Deferred Resolution | Lifetime Management | Hierarchical Lifetime Management | Per Resolve Lifetime Management | Externally Controlled Lifetime Management | Per Request Lifetime Management | Per Thread Lifetime Management | Dependency Injection and Unit Testing | Summary

Download code

Download PDF File

Order Paperback

Introduction

In previous chapters, you saw some of the reasons to use dependency injection and learned how dependency injection differs from other approaches to decoupling your application. In this chapter you'll see how you can use the Unity dependency injection container to easily add a dependency injection framework to your applications. On the way, you'll see some examples that illustrate how you might use Unity in a real-world application.

The Dependency Injection Lifecycle: Register, Resolve, Dispose

In the previous chapter, you saw how the ManagementController class has a constructor that expects to be injected with an object of type ITenantStore. The application must know at run time which implementation of the ITenantStore interface it should instantiate before it can go ahead and instantiate a ManagementController object. There are two things happening here: something in the application is making a decision about how to instantiate an object that implements the ITenantStore interface, and then something in the application is instantiating both that object and the ManagementController object. We will refer to the first task as registration and the second as resolution. At some point in the future, the application will finish using the ManagementController object and it will become available for garbage collection. At this point, it may also make sense for the garbage collector to dispose of the ITenantStore instance if other client classes do not share the same instance.

Dn178463.note(en-us,PandP.30).gifJana says:
Jana Typically, you perform the registration of the types that require dependency injection in a single method in your application; you should invoke this method early in your application’s lifecycle to ensure that the application is aware of all of the dependencies between its classes. Unity also supports configuring the container declaratively from a configuration file.

The Unity container can manage this register, resolve, dispose cycle making it easy to use dependency injection in your applications. The following sections illustrate this cycle using a simple example. Later in this chapter you will see a more sophisticated real-world sample and learn about some alternative approaches.

Dn178463.note(en-us,PandP.30).gifCarlos says:
Carlos You should always try to write container-agnostic code (except for the one place at the root of the application where you configure the container) in order to decouple your application from the specific dependency injection container you are using.

Register

Using the Unity container, you can register a set of mappings that determine what concrete type you require when a constructor (or property or method) identifies the type to be injected by an interface type or base class type. As a reminder, here is a copy of the constructor in the ManagementController class showing that it requires an injection of an object that implements the ITenantStore interface.

public ManagementController(ITenantStore tenantStore)
{
  this.tenantStore = tenantStore;
}

The following code sample shows how you could create a new Unity container and then register the concrete type to use when a ManagementController instance requires an ITenantStore instance.

var container = new UnityContainer();
container.RegisterType<ITenantStore, TenantStore>();

The RegisterType method shown here tells the container to instantiate a TenantStore object when it instantiates an object that requires an injection of an ITenantStore instance through a constructor, or method, or property. This example represents one of the simplest types of mapping that you can define using the Unity container. As you continue through this chapter, you will see other ways to register types and instances in the Unity container, that handle more complex scenarios and that provide greater flexibility.

Dn178463.note(en-us,PandP.30).gifMarkus says:
Markus You’ll see later that with Unity you can also register a class type directly without a mapping from an interface type.

Resolve

The usage of the RegisterType method shown in the previous section defines the mapping between the interface type used in the client class and the concrete type that you want to use in the application. To instantiate the ManagementController and TenantStore objects, you must invoke the Resolve method.

var controller = container.Resolve<ManagementController>();

Note that in this example, you do not instantiate the ManagementController object directly, rather you ask the Unity container to do it for you so that the container can resolve any dependencies. In this simple example, the dependency to resolve is for an ITenantStore object. Behind the scenes, the Unity container first constructs a TenantStore object and then passes it to the constructor of the ManagementController class.

Dispose

In the simple example shown in the previous two sections on registering and resolving types, the application stores a reference to the ManagementController object in the controller variable and the Unity container creates a new TenantStore instance to inject whenever you call the Resolve method. When the controller variable goes out of scope and becomes eligible for garbage collection, the TenantStore object will also be eligible for garbage collection.

Dn178463.note(en-us,PandP.30).gifMarkus says:
Markus By default, the Unity container doesn’t hold a reference to the objects it creates: to change this default behavior you need to use one of the Unity lifetime managers.

Registering and Resolving in your Code

One of the original motivations, discussed in Chapter 1, for a loosely coupled design and dependency injection was maintainability. One of the ways that dependency injection can help you to create more maintainable solutions is by describing, in a single location, how to compose your application from all of its constituent classes and components. From the perspective of Unity, this is the type registration information. Therefore, it makes sense to group all of the type registrations together in a single method that you invoke very early on in your application’s lifecycle; usually, directly in the application’s entry point. For example, in a web application, you could invoke the method that performs all of the registrations from within the Application_Start method in the global.asax.cs or global.asax.vb file, in a desktop application you invoke it from the Main method.

Dn178463.note(en-us,PandP.30).gifJana says:
Jana You should perform all the registrations in a single location in your code or in a configuration file. This makes it easy to manage the dependencies in your application. In a highly modular application, each module might be responsible for its own registration and manage its own container.
Using a configuration file for registrations can be a brittle and error prone solution. It can also lead to the illusion that this configuration can be changed without proper testing. Consider which settings, if any, need to be configurable after your solution is deployed.

Typically, you can call the Resolve method when you need an instance of a particular type in your application. The section “Lifetime Management” later in this chapter discusses the options for controlling the lifetime of objects resolved from the container: for example, do you want the container return a new instance each time you resolve a particular type, or should the container maintain a reference to the instance.

Adding Unity to Your Application

As a developer, before you can write any code that uses Unity, you must configure your Visual Studio project with all of the necessary assemblies, references, and other resources that you'll need. For information about how you can use NuGet to prepare your Visual Studio project to work with Unity, see the topic "Adding Unity to Your Application."

Dn178463.note(en-us,PandP.30).gifMarkus says:
Markus NuGet makes it very easy for you to configure your project with all of the prerequisites for using Unity.

A Real-World Example

The following example is taken from a web role implemented using ASP.NET MVC. You may find it useful to open the sample application, “DIwithUnitySample,” that accompanies this guide in Visual Studio while you read this section. At first sight the contents of this RegisterTypes method (in the ContainerBootstrapper class in the Surveys project) might seem to be somewhat complex; the next section will discuss the various type registrations in detail, and the following section will describe how the application uses these registrations to resolve the types it needs at runtime. This example also illustrates how you should perform all of the type registration in a single method in your application.

Dn178463.note(en-us,PandP.30).gifCarlos says:
Carlos It’s useful to adopt a standard name for the class that contains your type registration code; for example ContainerBootstrapper.
public static void RegisterTypes(IUnityContainer container)
  {
    var storageAccountType = typeof(StorageAccount);
    var retryPolicyFactoryType = typeof(IRetryPolicyFactory);
 
    // Instance registration
    StorageAccount account = 
      ApplicationConfiguration.GetStorageAccount("DataConnectionString");
    container.RegisterInstance(account);
 
    // Register factories
    container
      .RegisterInstance<IRetryPolicyFactory>(
        new ConfiguredRetryPolicyFactory())
      .RegisterType<ISurveyAnswerContainerFactory,
        SurveyAnswerContainerFactory>(
          new ContainerControlledLifetimeManager());
 
    // Register table types
    container
      .RegisterType<IDataTable<SurveyRow>, DataTable<SurveyRow>>(
        new InjectionConstructor(storageAccountType,
          retryPolicyFactoryType, Constants.SurveysTableName))
      ...
 
    // Register message queue type, use typeof with open generics
    container
      .RegisterType(
          typeof(IMessageQueue<>),
          typeof(MessageQueue<>),
          new InjectionConstructor(storageAccountType,
            retryPolicyFactoryType, typeof(String)));
 
    ...
 
    // Register store types
    container
      .RegisterType<ISurveyStore, SurveyStore>()
      .RegisterType<ITenantStore, TenantStore>()
      .RegisterType<ISurveyAnswerStore, SurveyAnswerStore>(
        new InjectionFactory((c, t, s) => new SurveyAnswerStore(
          container.Resolve<ITenantStore>(),
          container.Resolve<ISurveyAnswerContainerFactory>(),
          container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(
            new ParameterOverride(
              "queueName", Constants.StandardAnswerQueueName)),
          container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(
            new ParameterOverride(
              "queueName", Constants.PremiumAnswerQueueName)),
          container.Resolve<IBlobContainer<List<String>>>())));
  }
}

To see the complete ContainerBootstrapper class, you can open the DIwithUnitySample sample application that accompanies this guidance.

Figure 1 illustrates the object graph that the container will generate if a client resolves the ISurveyAnswerStore type from the container with the type registrations shown in the previous code sample.

Figure 1 - Resolving the ISurveyAnswerStore type

Figure 1 - Resolving the ISurveyAnswerStore type

Figure 1 illustrates the object graph that the container creates when you resolve the ISurveyAnswerStore type from the registrations shown in the previous code listing. There are some important points to note from Figure 1.

  • The container injects the SurveyAnswerStore with five objects that the container itself resolves: a TenantStore object, a SurveyAnswerContainerFactory object, an EntitiesBlobContainer object, and two MessageQueue objects. Note that an explicit factory delegate is used to determine what must be injected to create the store.
  • The container also resolves additional objects such as an EntitiesBlobContainer object and a FilesBlobContainer object to inject into the TenantStore instance.
  • Many of the objects instantiated by the container share the same instances of the RetryPolicyFactory and CloudStorageAccount objects which are registered using the RegisterInstance method. Instance registration is discussed in more detail later in this chapter.
  • The container injects the SurveyAnswerContainerFactory instance with an instance of the Unity container. Note that as a general rule, this is not a recommended practice.

The following sections discuss all of these points (and more) in detail. Figure 1 is intended to give an idea of what you can achieve with dependency injection in your applications.

Type Registrations in the Example

The previous code listing gives examples of many of the different types of registration that you can perform with the Unity container. This section examines each part of the registration individually.

Dn178463.note(en-us,PandP.30).gifJana says:
Jana Bear in mind, that if your registrations start to become too complicated or fragile, you are probably doing it wrong.

Instance Registration

The simplest type of registration is instance registration where the container is responsible for maintaining a reference to a singleton instance of a type. For example:

StorageAccount account = 
  ApplicationConfiguration.GetStorageAccount("DataConnectionString");
container.RegisterInstance(account);

Here, instead of registering a mapping for a type to resolved later, the application creates a CloudStorageAccount object and registers the instance with the container. This means that the CloudStorageAccount object is created at registration time, and that only a single instance of the object exists in the container. This single instance is shared by many of the other objects that the container instantiates. Figure 1 shows that many of the objects that the container creates when a client resolves the ISurveyAnswerStore type share this CloudStorageAccount object instance.

You can also use the ContainerControlledLifetimeManager class with the RegisterType method to create a singleton instance where the container maintains a reference to the object. The section “Lifetime Management” later in this chapter covers this in more detail.

Simple Type Registration

The most common type registration you will see maps an interface type to a concrete type. For example:

container.RegisterType<ISurveyStore, SurveyStore>();

Later, you can resolve the ISurveyStore type as shown in the following example, and the container will inject any of the required dependencies into the SurveyStore object that it creates.

var surveyStore = container.Resolve<ISurveyStore>();
Dn178463.note(en-us,PandP.30).gifCarlos says:
Carlos If the SurveyStore class has multiple constructors with the same number of parameters you can use either the InjectionConstructor attribute, the API, or the configuration file to disambiguate between the different SurveyStore constructors. However, although InjectionConstructor attributes are easy to use, they do couple your code to the container.
In most cases, components should have a single constructor and the constructor defines the dependencies of that component.

Constructor Injection

The following code sample shows the constructor for the DataTable class that takes three parameters.

public DataTable(StorageAccount account,
  IRetryPolicyFactory retryPolicyFactory, string tableName)
{
  ...
}

The registrations for the DataTable types in the container includes an InjectionConstructor that defines how the container should resolve the parameter types. The container passes to the constructor references to the registered StorageAccount and RetryPolicyFactory instances, and a string that specifies the name of the table to use.

container
  .RegisterType<IDataTable<SurveyRow>, DataTable<SurveyRow>>(
    new InjectionConstructor(storageAccountType,
      retryPolicyFactoryType, Constants.SurveysTableName))
  .RegisterType<IDataTable<QuestionRow>, DataTable<QuestionRow>>(
    new InjectionConstructor(storageAccountType,
      retryPolicyFactoryType, Constants.QuestionsTableName));

The sample application uses a similar approach to register the blob container types it uses:

container
  .RegisterType<IBlobContainer<List<string>>,
    EntitiesBlobContainer<List<string>>>(
      new InjectionConstructor(storageAccountType,
        retryPolicyFactoryType, Constants.SurveyAnswersListsBlobName))
  .RegisterType<IBlobContainer<Tenant>,
    EntitiesBlobContainer<Tenant>>(
      new InjectionConstructor(storageAccountType,
        retryPolicyFactoryType, Constants.TenantsBlobName))
  .RegisterType<IBlobContainer<byte[]>,
    FilesBlobContainer>(
      new InjectionConstructor(storageAccountType,
        retryPolicyFactoryType, Constants.LogosBlobName, "image/jpeg"))
  .RegisterType<IBlobContainer<SurveyAnswer>,
    EntitiesBlobContainer<SurveyAnswer>>(
      new InjectionConstructor(storageAccountType,
        retryPolicyFactoryType, typeof(string)));

Unity supports property and method injection in addition to the constructor injection shown in this example. If you use property injection then, as with any property, you should ensure that any properties have a useful default value. It is easy to forget to set a property.

Dn178463.note(en-us,PandP.30).gifMarkus says:
Markus Both the storage account and retry policy factory are singletons. The storage account is registered using the RegisterInstance method, the retry policy factory is registered using the ContainerControlledLifetimeManager class that you’ll learn more about later in this chapter.

Registering Open Generics

The example code uses a slightly different approach to register the message queue types: it uses an overload of the RegisterTypes method that takes types as standard parameters instead of using type parameters.

container
  .RegisterType(
    typeof(IMessageQueue<>),
    typeof(MessageQueue<>),
    new InjectionConstructor(storageAccountType,
      retryPolicyFactoryType, typeof(string)));

This approach enables you to resolve the message queue type with any type parameter. The example uses the SurveyAnswerStoredMessage type:

container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(...);

Parameter Overrides

The ContainerBootstrapper class contains several examples where one of the InjectionConstructor constructor parameters is typeof(string). For example, in the message queue registration and in the blob container for survey answers registration:

container.RegisterType(
  typeof(IMessageQueue<>),
  typeof(MessageQueue<>),
  new InjectionConstructor(storageAccountType,
    retryPolicyFactoryType, typeof(string)));

...

container.RegisterType<IBlobContainer<SurveyAnswer>,
  EntitiesBlobContainer<SurveyAnswer>>(
    new InjectionConstructor(storageAccountType,
      retryPolicyFactoryType, typeof(string)));

The container does not include a registration that it can use to resolve this type. Therefore, when you resolve either the IMessageQueue<> or IBlobContainer<SurveyAnswer> types, you must provide a value for this parameter otherwise the resolution will fail. This provides a convenient method to pass parameter values that aren’t known at registration time to instances created by the container using the ParameterOverride type.

Resolving Types in the Example

The example solution performs the type registration described in the previous section in three locations: in a standalone application that initializes the storage, in the web application’s start-up phase, and in a factory class.

Simple Resolve

The usage in this simple standalone application is straightforward: it calls the RegisterTypes method to perform all the registration, resolves a number of objects, and then invokes the Initialize method on each of them to perform some initialization work before the application terminates. The following code sample shows this.

static void Main(string[] args)
{
  using (var container = new UnityContainer())
  {
    ContainerBootstrapper.RegisterTypes(container);

    container.Resolve<ISurveyStore>().Initialize();
    container.Resolve<ISurveyAnswerStore>().Initialize();
    container.Resolve<ITenantStore>().Initialize();
 
    Console.WriteLine("Done");
    Console.ReadLine();
  }
}

In this example, after the Initialization methods have run, the container is disposed.

Resolving in an MVC Application

The usage in the MVC application is more sophisticated: the application configures a container that the application will use at start-up, and then resolves the various types as and when it needs them. Remember that this is an ASP.NET MVC application; therefore, the container must be able to inject the MVC controller classes with the various store and queue objects that they need. The “Unity bootstrapper for ASP.NET MVC” NuGet package (search for Unity3 in the NuGet package manager) simplifies this by adding libraries and source code to the project in Visual Studio. The following code sample shows the RegisterTypes method in the UnityConfig class that the NuGet package added to the project; you can choose to load the Unity configuration from your configuration file or add the registrations directly.

public static void RegisterTypes(IUnityContainer container)
{
    // NOTE: To load from web.config uncomment the line below...
    // container.LoadConfiguration();

    // TODO: Register your types here
    // container.RegisterType<IProductRepository, ProductRepository>();
}

The “Unity bootstrapper for ASP.NET MVC” provides a UnityDependencyResolver class that resolves controllers from the container. If you need to configure injection for the controller classes then you need to add the registration manually or add injection attributes to the controller classes

The following code sample shows part of the ManagementController class that custom factory class can resolve along with its dependency on the ITenantStore type from the registration information.

public class ManagementController : Controller
{
  private readonly ITenantStore tenantStore;
 
  public ManagementController(ITenantStore tenantStore)
  {
    this.tenantStore = tenantStore;
  }
     ...
}

Using the Per Request Lifetime Manager in MVC and WebAPI Application

The previous example showed how to use the “Unity bootstrapper for ASP.NET MVC” NuGet package to handle registering and resolving controllers in an MVC application. The package also includes a PerRequestLifetime manager that you can use in an MVC application. This lifetime manager enables you to create instances of registered types that behave like singletons within the scope of an HTTP request.

If you are working with an ASP.NET Web API project, there is a “Unity bootstrapper for ASP.NET WebApi” NuGet package that offers equivalent features (search for Unity3 in the NuGet package manager). You can use both the “Unity bootstrapper for ASP.NET WebApi” and “Unity bootstrapper for ASP.NET MVC” packages in the same project and they will share a single container configuration class.

Note

There are third-party solutions available that offer similar support for ASP.NET WCF applications.

Resolving with Run Time Information

You don’t always know the values that you need to construct a dependency at design time. In the example shown below, a user provides the name of the blob container that the application must create at run time. In this example, type resolution occurs in a factory class that determines the value of a constructor parameter at registration time. The following code sample shows this factory class.

public class SurveyAnswerContainerFactory : ISurveyAnswerContainerFactory
{
  private readonly IUnityContainer unityContainer;
 
  public SurveyAnswerContainerFactory(IUnityContainer unityContainer)
  {
    this.unityContainer = unityContainer;
  }
 
  public IBlobContainer<SurveyAnswer> Create(string tenant, string surveySlug)
  {
    var blobContainerName = string.Format(
        CultureInfo.InvariantCulture,
        "surveyanswers-{0}-{1}",
        tenant.ToLowerInvariant(),
        surveySlug.ToLowerInvariant());
    return this.unityContainer.Resolve<IBlobContainer<SurveyAnswer>>(
        new ParameterOverride("blobContainerName", blobContainerName));
  }
}

In this example, the Resolve method uses a parameter override to provide a value for the blobContainerName parameter to the constructor of the EntitiesBlobContainer class that is registered in the container instance injected into the SurveyAnswerContainerFactory object. Figure 1 shows how the SurveyAnswerContainerFactory object is injected with a Unity container instance when it is resolved.

Dn178463.note(en-us,PandP.30).gifCarlos says:
Carlos Because the application supplies the name of the blob container to create at run time, the factory class uses a parameter override to supply this value to the Resolve method.

You saw previously how the application registered the IBlobContainer<SurveyAnswer>> type using a string parameter in the injection constructor. Without the parameter override, this registration would fail because the container cannot resolve the string type.

You can also see the parameter overrides in use in the ContainerBootstrapper class as part of the registration of the survey answer store. In this example, the parameter overrides provide the name of the message queues to create. The parameter overrides are supplied at resolve time when the registered InjectionFactory executes.

container
  .RegisterType<ISurveyAnswerStore, SurveyAnswerStore>(
    new InjectionFactory((c, t, s) => new SurveyAnswerStore(
      container.Resolve<ITenantStore>(),
      container.Resolve<ISurveyAnswerContainerFactory>(),
      container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(
        new ParameterOverride(
          "queueName", Constants.StandardAnswerQueueName)),
      container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(
        new ParameterOverride(
          "queueName", Constants.PremiumAnswerQueueName)),
      container.Resolve<IBlobContainer<List<string>>>())));

Registration

In this section, you’ll learn more about how you can register types with the Unity container and the advantages and disadvantages of the different approaches. All of the examples you’ve seen so far have registered types with the Unity container programmatically by using methods such as RegisterType and RegisterInstance.

Programmatically configuring a Unity container at runtime is convenient, and if you keep all of your registration code together, it makes it easy to change those registrations when you modify the application. However, it does mean that you must recompile the application if you need to change your registrations. In some scenarios, you may want a mechanism that enables you to change the registrations in a configuration file and cause your application to use a different set of concrete classes at run time.

Named Type Registrations

Previously, you saw an example of how you can use parameter overrides to provide the name of the message queue when you are resolving the IMessageQueue type. An alternative approach for this scenario is to use named type registrations. In this case the message queue registration looks like the following where the two alternative registrations are named “Standard” and “Premium”:

container
  .RegisterType<IMessageQueue<SurveyAnswerStoredMessage>,
    MessageQueue<SurveyAnswerStoredMessage>>(
    "Standard",
    new InjectionConstructor(storageAccountType, retryPolicyFactoryType,
      Constants.StandardAnswerQueueName))
  .RegisterType<IMessageQueue<SurveyAnswerStoredMessage>,
    MessageQueue<SurveyAnswerStoredMessage>>(
    "Premium",
    new InjectionConstructor(storageAccountType, retryPolicyFactoryType,
      Constants.PremiumAnswerQueueName));

With this registration, you can now resolve the message queue parameters to the SurveyAnswerStore constructor as follows using the named registrations:

container
  .RegisterType<ISurveyAnswerStore, SurveyAnswerStore>(
    new InjectionFactory((c, t, s) => new SurveyAnswerStore(
      container.Resolve<ITenantStore>(),
      container.Resolve<ISurveyAnswerContainerFactory>(),
      container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(
      "Standard"),
      container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(
      "Premium"),
      container.Resolve<IBlobContainer<List<string>>>())));

Design-Time Configuration

Unity enables you to load a collection of registrations from a configuration file into a container. For example, you could add the following sections to your app.config or web.config file to register mapping from the ITenantStore interface to the TenantStore class.

Note

You cannot use design-time configuration for Unity containers in Windows Store apps. For more information, see Appendix A – Unity and Windows Store apps.

<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity xmlns="https://schemas.microsoft.com/practices/2010/unity">
    <namespace name="Tailspin.Web.Survey.Shared.Stores" />
    <container>
      <register type="ITenantStore" mapTo="TenantStore" />
    </container>
  </unity>
</configuration>

For more information about the structure of this configuration file, see the topic Design Time Configuration.

To load the registration details from the configuration file, you can use the following code. The LoadConfiguration extension method is defined in the Microsoft.Practices.Unity.Configuration namespace.

IUnityContainer container = new UnityContainer();
container.LoadConfiguration();
Dn178463.note(en-us,PandP.30).gifPoe says:
Poe Defining the registrations in a configuration file means that it’s possible to make changes without recompiling the application. This can be useful for customized deployments and troubleshooting. You can also adopt a hybrid approach.

Note

If your Unity configuration includes any sensitive information, you should encrypt it. For more information, see Encrypting Configuration Information Using Protected Configuration on MSDN.

Registration by Convention

This feature (also known as auto-registration) is intended to minimize the amount of type registration code that you need to write. You may find it useful to open the sample application, “OtherUnitySamples,” that accompanies this guide in Visual Studio while you read this section. Rather than specify each type mapping individually, you can direct the Unity container to scan a collection of assemblies and then automatically register multiple mappings based on a set of rules. If you only have a handful of simple registrations, it doesn’t make sense to use this feature, but if you have many types to register it will save you a considerable amount of effort.

Dn178463.note(en-us,PandP.30).gifCarlos says:
Carlos In many cases, you don’t need to register a type to resolve it because Unity’s auto-wiring will figure it out for you. You do need to explicitly configure mappings though, and for this the registration by convention feature may prove useful.

Note

This feature is only supported when you are configuring Unity programmatically. You can’t specify registration by convention in the configuration file.

The registration by convention feature can scan a collection of assemblies, and then create a set of mappings in a Unity container for some or all of the types it discovers in the assemblies. Additionally, you can specify the lifetime managers to use (these are described in more detail later in this chapter) and the details of any injection parameters. You can easily modify the set of rules included out-of-the-box to implement more sophisticated scenarios.

Dn178463.note(en-us,PandP.30).gifBeth says:
Beth Registration by convention is intended to simplify registering types with the Unity container when you have a large number of types that must be registered with similar settings.

The following samples illustrate how you can use the registration by convention feature to create mappings in the Unity container using the RegisterTypes method. These examples are based on the code in the OtherUnitySamples Visual Studio solution included with this guidance. The RegisterTypes method has the following parameters:

Parameter

Description

Types

This parameter is an enumerable collection of types that you want to register with the container. These are the types that you want to register directly or create mappings to. You can create this collection by providing a list of types directly or by using one of the methods of the built-in AllClasses helper class: for example, the method FromLoadedAssemblies loads all of the available types from the currently loaded assemblies.

You can use LINQ to filter this enumeration.

getFromTypes

This optional parameter identifies the types you want to map from in the container. The built-in WithMappings helper class provides several options for this mapping strategy: for example, the MatchingInterface property creates mappings where there are interfaces and implementations that follow the naming convention ITenant and Tenant.

getName

This optional parameter enables you to control whether to create default registrations or named registrations for the types. The built-in helper class WithName, enables you to choose between using default registrations or named registrations that use the type name.

getLifeTimeManager

This optional parameter enables you to select from the built-in lifetime managers.

getInjectionMembers

This optional parameter enables you to provide definitions for any injection members for the types that you are registering.

overwriteExistingMappings

This optional parameter enables you to control how the method behaves if it detects an attempt to overwrite an existing mapping in the Unity container. By default, the RegisterTypes method throws an exception if it detects such an attempt. If this parameter is true, the method silently overwrites an existing mapping with a new one based on the values of the other parameters.

The first example shows how you can create registrations for all the types that implement an interface where the ITenant/Tenant naming convention is in use.

var container = new UnityContainer();

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.MatchingInterface,
    WithName.Default);
}

This creates a set of transient registrations that map interfaces to types in the container.

The following example creates named registrations and uses the ContainerControlledLifetimeManager type to ensure that resolving from the container results in singletons.

var container = new UnityContainer();

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.MatchingInterface,
    WithName.TypeName,
    WithLifetime.ContainerControlled);

Because this example is using the lifetime manager, it registers all loaded types in addition to mapping any interfaces to their matching types.

Lifetime managers are discussed later in this chapter in the section “Lifetime Management.”

In some scenarios, you may need to combine registration by convention with explicit registration. You can use registration by convention to perform the basic registration of multiple types, and then explicitly add information for specific types. The following example adds an InjectionConstructor to the type registration for the TenantStore class that was one of the types registered by calling the RegisterTypes method.

var container = new UnityContainer();

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.MatchingInterface,
    WithName.Default,
    WithLifetime.ContainerControlled);
 
  // Provide some additional information for this registration
  container.RegisterType<TenantStore>(new InjectionConstructor("Adatum"));

The examples you’ve seen so far use the FromLoadedAssemblies method to provide a list of assemblies to scan for types; you may want to filter this list so that you only register a subset of the types from these assemblies. The following sample shows how to create a filter based on the namespace containing the type. In this example, only types in the OtherUnitySamples namespace are registered in the container.

var container = new UnityContainer();

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
      t => t.Namespace == "OtherUnitySamples"),
    WithMappings.MatchingInterface,
    WithName.Default,
    WithLifetime.ContainerControlled);

The next example illustrates the use of the getInjectionMembers parameter: this enables you specify types that should be injected when the registered type is resolved from the container. Note that any types to be injected will be injected into all the types registered in the container by the call to the RegisterTypes method. The following example assumes that all of the types registered have a constructor with a string parameter: any attempt to resolve a type without such a constructor parameter will result in an exception being thrown from the container.

var container = new UnityContainer();

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
      new InjectionConstructor("Adatum")
    });

A more practical use of the getInjectionMembers method is to use it to configure interception for all of the registered types (for more information about interception in Unity, see Chapter 5, “Interception with Unity”). In the following example, the registration by convention injects all of the registered types with the custom LoggingInterceptionBehavior type using virtual method interception.

var container = new UnityContainer();

container.AddNewExtension<Interception>();
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
      t => t.Namespace == "OtherUnitySamples"),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
      new Interceptor<VirtualMethodInterceptor>(),
      new InterceptionBehavior<LoggingInterceptionBehavior>()
    });
Dn178463.note(en-us,PandP.30).gifMarkus says:
Markus You can keep the list of classes in the OtherUnitySamples namespace to use in other calls to the RegisterTypes method to avoid the need to re-scan the assemblies.

Note how this example uses a filter to ensure that only types in the OtherUnitySamples namespace are registered in the container. Without this filter, the container will try to inject the interceptor into all the types from the loaded assemblies: this includes the LoggingInterceptionBehavior type itself and this results in a stack overflow.

The block provides helper classes such as the AllClasses class that you can use as parameters to the RegisterTypes method. You can create your own helper classes, or use a lambda such the one used for the getInjectionMembers parameter in the previous example, to customize the behavior of registration by convention to your own requirements.

The following artificial example shows how the overwriteExistingMappings parameter prevents the RegisterTypes method from throwing an exception if you attempt to overwrite an existing mapping. The result is that the container contains a mapping of the ITenantStore interface type to the TenantStore2 type.

var container = new UnityContainer();

container.RegisterTypes(
    new[] { typeof(TenantStore), typeof(TenantStore2) },
    t => new[] { typeof(ITenantStore) },
    overwriteExistingMappings: true);

The mapping for the last type overwrites the previous mapping in the container.

Dn178463.note(en-us,PandP.30).gifJana says:
Jana Be cautious when you use registration by convention and consider the implications of registering all of the types discovered by the RegisterTypes method using the same options.

You can extend the abstract RegistrationConvention class to define a reusable convention that you can pass to the RegisterTypes method as a single parameter. The following sample shows a how you can extend the RegistrationConvention class.

class SampleConvention : RegistrationConvention
{
  public override Func<Type, IEnumerable<Type>> GetFromTypes()
  {
    return t => t.GetTypeInfo().ImplementedInterfaces;
  }
 
  public override Func<Type, IEnumerable<InjectionMember>> GetInjectionMembers()
  {
    return null;
  }
 
  public override Func<Type, LifetimeManager> GetLifetimeManager()
  {
    return t => new ContainerControlledLifetimeManager();
  }
 
  public override Func<Type, string> GetName()
  {
    return t => t.Name;
  }
 
  public override IEnumerable<Type> GetTypes()
  {
    yield return typeof(TenantStore);
    yield return typeof(SurveyStore);
  }
}

Registration by Convention and Generic Types

You can use registration by convention to register generic types. The following interface and class definitions use a generic type and you can use the WithMappings.FromMatchingInterface helper method to create a mapping between these types in the container.

public interface ICustomerStore<T>
{
  ...
}
 
public class CustomerStore<T> : ICustomerStore<T>
{
  ...
}

This registers the open generic types but enables you to resolve using a closed generic. For example, you could resolve instances using the following code.

var blobCustomerStore = container.Resolve<ICustomerStore<BlobStorage>>();
var tableCustomerStore = container.Resolve<ICustomerStore<TableStorage>>();

It’s also possible to combine using registration by convention to register mappings for open generic types with a specific registration a closed generic type as shown in the following sample. The closed type registration will always take priority.

container.RegisterTypes(
  // Registers open generics
  AllClasses.FromLoadedAssemblies(),
  WithMappings.FromMatchingInterface,
  WithName.Default);
 
// Add a registration for a closed generic type
container.RegisterType<ICustomerStore<TableStorage>,
                       CustomerStore<TableStorage>>();

Using Child Containers

Although you can use named registrations to define different mappings for the same type, an alternative approach is to use a child container. The following code sample illustrates how to use a child container to resolve the IMessageQueue<SurveyAnswerStoredMessage> type with a different connection string.

var storageAccountType = typeof(StorageAccount);

var storageAccount = ApplicationConfiguration
  .GetStorageAccount("DataConnectionString");
container.RegisterInstance(storageAccount);

container
  .RegisterType<IMessageQueue<SurveyAnswerStoredMessage>,
      MessageQueue<SurveyAnswerStoredMessage>>(
        "Standard",
        new InjectionConstructor(storageAccountType,
          "StandardAnswerQueue"),
        retryPolicyFactoryProperty);

var childContainer = container.CreateChildContainer();
var alternateAccount = ApplicationConfiguration
  .GetStorageAccount("AlternateDataConnectionString");
childContainer.RegisterInstance(alternateAccount);

childContainer
  .RegisterType<IMessageQueue<SurveyAnswerStoredMessage>, 
    MessageQueue<SurveyAnswerStoredMessage>>(
      "Standard",
        new InjectionConstructor(storageAccountType,
          "StandardAnswerQueue"),
        retryPolicyFactoryProperty);

You can now resolve the type IMessageQueue<SurveyAnswerStoredMessage> from either the original parent container or the child container. Depending on which container you use, the MessageQueue instance is injected with a different set of account details.

The advantage of this approach over using different named registrations, is that if you attempt to resolve a type from the child container and that type is not registered in the child container, then Unity will automatically fall back to try and resolve the type from the parent container.

Note

You can also use child containers to manage the lifetime of objects. This use of child containers is discussed later in this chapter.

Viewing Registration Information

You can access the registration data in the container programmatically if you want to view details of the registration information. The following code sample shows a basic approach to viewing the registrations in a container.

Console.WriteLine("Container has {0} Registrations:",
  container.Registrations.Count());
foreach (ContainerRegistration item in container.Registrations)
{
  Console.WriteLine(item.GetMappingAsString());
}

This example uses an extension method called GetMappingAsString to display formatted output. The output using the registrations shown at the start of this chapter looks like the following:

Container has 14 Registrations:
+ IUnityContainer  '[default]'  Container
+ StorageAccount  '[default]'  ContainerControlled
+ IRetryPolicyFactory  '[default]'  ContainerControlled
+ IDataTable`1<SurveyRow> -> DataTable`1<SurveyRow>  '[default]'  Transient
+ IDataTable`1<QuestionRow> -> DataTable`1<QuestionRow>  '[default]'  Transient
+ IMessageQueue`1<SurveyAnswerStoredMessage> -> 
  MessageQueue`1<SurveyAnswerStoredMessage>  'Standard'  Transient
+ IMessageQueue`1<SurveyAnswerStoredMessage> -> 
  MessageQueue`1<SurveyAnswerStoredMessage>  'Premium'  Transient
+ IBlobContainer`1<List`1<String>> -> EntitiesBlobContainer`1<List`1<String>>  
  '[default]'  Transient
+ IBlobContainer`1<Tenant> -> EntitiesBlobContainer`1<Tenant>  '[default]'  Transient
+ IBlobContainer`1<Byte[]> -> FilesBlobContainer  '[default]'  Transient
+ ISurveyStore -> SurveyStore  '[default]'  Transient
+ ITenantStore -> TenantStore  '[default]'  Transient
+ ISurveyAnswerStore -> SurveyAnswerStore  '[default]'  Transient
+ ISurveyAnswerContainerFactory -> SurveyAnswerContainerFactory  '[default]'  
  Transient
Dn178463.note(en-us,PandP.30).gifPoe says:
Poe Having a utility that can display your registrations can help troubleshoot issues. This is especially useful if you define the registrations in a configuration file. However, getting registration information is expensive and you should only do it to troubleshoot issues.

The following code sample shows the extension method that creates the formatted output.

static class ContainerRegistrationsExtension
{
  public static string GetMappingAsString(
    this ContainerRegistration registration)
  {
    string regName, regType, mapTo, lifetime;
 
    var r = registration.RegisteredType;
    regType = r.Name + GetGenericArgumentsList(r);
 
    var m = registration.MappedToType;
    mapTo = m.Name + GetGenericArgumentsList(m);
 
    regName = registration.Name ?? "[default]";
 
    lifetime = registration.LifetimeManagerType.Name;
    if (mapTo != regType)
    {
      mapTo = " -> " + mapTo;
    }
    else
    {
      mapTo = string.Empty;
    }
    lifetime = lifetime.Substring(
      0, lifetime.Length - "LifetimeManager".Length);
    return String.Format(
      "+ {0}{1}  '{2}'  {3}", regType, mapTo, regName, lifetime);
  }
 
  private static string GetGenericArgumentsList(Type type)
  {
    if (type.GetGenericArguments().Length == 0) return string.Empty;
    string arglist = string.Empty;
    bool first = true;
    foreach (Type t in type.GetGenericArguments())
    {
      arglist += first ? t.Name : ", " + t.Name;
      first = false;
      if (t.GetGenericArguments().Length > 0)
      {
        arglist += GetGenericArgumentsList(t);
      }
    }
    return "<" + arglist + ">";
  }
}

Resolving

You have already seen some sample code that shows some simple cases of resolving types from the Unity container. For example:

var surveyStore = container.Resolve<ISurveyStore>();
container.Resolve<IMessageQueue<SurveyAnswerStoredMessage>>(
  "Premium");

The second of these two examples shows how to resolve a named type registration from the container.

You can override the registration information in the container when you resolve a type. The following code sample uses a dependency override to specify the type of controller object to create:

protected override IController GetControllerInstance(
  RequestContext requestContext, Type controllerType)
{
  return this.container.Resolve(controllerType,
    new DependencyOverride<RequestContext>(requestContext)) as IController;
}

This example assumes that there is no registration in the container for the controller type that is passed to the GetControllerInstance method, so the dependency override defines a registration as the type is resolved. This enables the container to resolve any other dependencies in the controller class. You can use a dependency override to override an existing registration in addition to providing registration information that isn’t registered with the container.

The SurveyAnswerContainerFactory class uses a parameter override to specify the value of a constructor parameter that the application cannot know until run time.

Resolving in an ASP.NET Web Application

In the example shown earlier in this chapter, you saw how to integrate Unity into an MVC application, so that you can use Unity to resolve any dependencies in your MVC controller classes by creating a custom MVC controller factory.

Standard ASP.NET web applications face a similar problem: how do you resolve any dependencies in your web page classes when you have no control over how and when ASP.NET instantiates your page objects. The aExpense reference implementation demonstrates how you can address this issue.

The following code sample shows part of a page class in the aExpense web application.

public partial class Default : Page
{
    [Dependency]
    public IExpenseRepository Repository { get; set; }

    protected void Page_Init(object sender, EventArgs e)
    {
        this.ViewStateUserKey = this.User.Identity.Name;
    }

    protected void Page_Load(object sender, EventArgs e)
    {            
        var expenses = Repository.GetExpensesByUser(this.User.Identity.Name);
        this.MyExpensesGridView.DataSource = expenses;
        this.DataBind();
    }
...
}

This example shows a property, of type IExpenseRepository decorated with the Dependency attribute, and some standard page life-cycle methods, one of which uses the Repository property. The Dependency attribute marks the property for property setter injection by the Unity container.

The following code sample shows the registration of the IExpenseRepository type.

public static void Configure(IUnityContainer container)
{
    container
        .RegisterInstance<IExpenseRepository>(new ExpenseRepository())
        .RegisterType<IProfileStore, SimulatedLdapProfileStore>()
        .RegisterType<IUserRepository, UserRepository>(
            new ContainerControlledLifetimeManager());
    ...
}

The following code sample, from the Global.asax.cs file, shows how the web application performs the type registration in the Application_Start method, and uses the BuildUp method in the Application_PreRequestHandlerExecute method to perform the type resolution.

public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        IUnityContainer container = Application.GetContainer();
        ContainerBootstrapper.Configure(container);
    }

    ...

    protected void Application_PreRequestHandlerExecute(
        object sender, EventArgs e)
    {
        var handler =
            HttpContext.Current.Handler as System.Web.UI.Page;

        if (handler != null)
        {
            var container = Application.GetContainer();

            if (container != null)
            {
                container.BuildUp(handler.GetType(), handler);
            }
        }
    }
}

The BuildUp method passes an existing object, in this case the ASP.NET page object, through the container so that the container can inject any dependencies into the object.

Dn178463.note(en-us,PandP.30).gifCarlos says:
Carlos Using the BuildUp method, you can only perform property and method injection. You cannot perform constructor injection because the object has already been created.

Resolving in a WCF Service

If you want to use Unity to automatically resolve types in a WCF service, you need to modify the way that WCF instantiates the service so that Unity can inject any dependencies. The example in this section is based on a simple WCF calculator sample, and the following example code shows the interface and part of the service class. You may find it useful to open the sample application, “UnityWCFSample,” that accompanies this guide in Visual Studio while you read this section. The example uses constructor injection, but you could just as easily use method or property setter injection if required.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
  [OperationContract]
  double Add(double n1, double n2);
  [OperationContract]
  double Subtract(double n1, double n2);
  [OperationContract]
  double Multiply(double n1, double n2);
  [OperationContract]
  double Divide(double n1, double n2);
}

public class CalculatorService : ICalculator
{
  private ICalculationEngine calculatorEngine;

  public CalculatorService(ICalculationEngine calculatorEngine)
  {
    this.calculatorEngine = calculatorEngine;
  }

  public double Add(double n1, double n2)
  {
    double result = calculatorEngine.Add(n1, n2);
    Console.WriteLine("Received Add({0},{1})", n1, n2);
    Console.WriteLine("Return: {0}", result);
    return result;
  }

  ...
}

To modify WCF to use Unity to instantiate the service, you must provide a custom ServiceHost class that can pass a Unity container instance into the WCF infrastructure as shown in the following example.

public class UnityServiceHost : ServiceHost
{
  public UnityServiceHost(IUnityContainer container,
    Type serviceType, params Uri[] baseAddresses)
    : base(serviceType, baseAddresses)
  {
    if (container == null)
    {
      throw new ArgumentNullException("container");
    }

    foreach (var cd in this.ImplementedContracts.Values)
    {
      cd.Behaviors.Add(new UnityInstanceProvider(container));
    }
  }

The following code sample shows the UnityInstanceProvider class that resolves the service type (the CalculatorService type in this example) from the Unity container.

public class UnityInstanceProvider
  : IInstanceProvider, IContractBehavior
{
  private readonly IUnityContainer container;

  public UnityInstanceProvider(IUnityContainer container)
  {
    if (container == null)
    {
      throw new ArgumentNullException("container");
    }

    this.container = container;
  }

  #region IInstanceProvider Members

  public object GetInstance(InstanceContext instanceContext,
    Message message)
  {
    return this.GetInstance(instanceContext);
  }

  public object GetInstance(InstanceContext instanceContext)
  {
    return this.container.Resolve(
      instanceContext.Host.Description.ServiceType);
  }

  public void ReleaseInstance(InstanceContext instanceContext,
    object instance)
  {
  }

  #endregion

  #region IContractBehavior Members

  public void AddBindingParameters(
    ContractDescription contractDescription,
    ServiceEndpoint endpoint,
    BindingParameterCollection bindingParameters)
  {
  }

  public void ApplyClientBehavior(
    ContractDescription contractDescription,
    ServiceEndpoint endpoint, ClientRuntime clientRuntime)
  {
  }

  public void ApplyDispatchBehavior(
    ContractDescription contractDescription,
    ServiceEndpoint endpoint,
    DispatchRuntime dispatchRuntime)
  {
    dispatchRuntime.InstanceProvider = this;
  }

  public void Validate(
    ContractDescription contractDescription,
    ServiceEndpoint endpoint)
  {
  }

  #endregion
}

Now that you have defined the new UnityServiceHost class that uses Unity to instantiate your WCF service, you must create an instance of the UnityServiceHost class in your run time environment. How you do this for a self-hosted service is different from how you do it for a service hosted in IIS or WAS.

Using the UnityServiceHost Class with a Self-hosted Service

If you are self-hosting the service, you can instantiate the UnityServiceHost class directly in your hosting application and pass it a Unity container as shown in the following code sample.

class Program
{
  static void Main(string[] args)
  {
    // Register types with Unity
    using (IUnityContainer container = new UnityContainer())
    {
      RegisterTypes(container);

      // Step 1 Create a URI to serve as the base address.
      Uri baseAddress = new Uri("https://localhost:8000/GettingStarted/");

      // Step 2 Create a ServiceHost instance
      ServiceHost selfHost = new UnityServiceHost(container, 
        typeof(CalculatorService.CalculatorService), baseAddress);


      try
      {
        // Step 3 Add a service endpoint.
        selfHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), 
          "CalculatorService");

        // Step 4 Enable metadata exchange.
        ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
        smb.HttpGetEnabled = true;
        selfHost.Description.Behaviors.Add(smb);

        // Step 5 Start the service.
        selfHost.Open();
        Console.WriteLine("The service is ready.");
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHostBase to shutdown the service.
        selfHost.Close();
      }
      catch (CommunicationException ce)
      {
        Console.WriteLine("An exception occurred: {0}", ce.Message);
        selfHost.Abort();
      }
    }
  }

  private static void RegisterTypes(IUnityContainer container)
  {
    container.RegisterType<ICalculationEngine, SimpleEngine>();
  }
}

Using the UnityServiceHost Class with Service Hosted in IIS or WAS

If you are hosting your WCF service in IIS or WAS it is a little more complex because you can no longer directly create a service host and by default, IIS will create a ServiceHost and not a UnityServiceHost instance. To get around this problem, you must create a service host factory as shown in the following code sample.

class UnityServiceHostFactory : ServiceHostFactory
{
  private readonly IUnityContainer container;

  public UnityServiceHostFactory()
  {
    container = new UnityContainer();
    RegisterTypes(container);
  }

  protected override ServiceHost CreateServiceHost(
    Type serviceType, Uri[] baseAddresses)
  {
    return new UnityServiceHost(this.container,
      serviceType, baseAddresses);
  }

  private void RegisterTypes(IUnityContainer container)
  {
    container.RegisterType<ICalculationEngine, SimpleEngine>();
  }
}

This factory class creates a Unity container instance and passes it in to the constructor of the new UnityServiceHost class.

The final step is to instruct IIS or WAS to use the factory to create a service host. You can do this in the .svc file for the service as shown in the following example.

<%@ ServiceHost Language="C#" Debug="true" 
Service="CalculatorService.CalculatorService" 
Factory="CalculatorService.UnityServiceHostFactory" %>

Automatic Factories

Sometimes, your application does not know all the details of the objects to construct until run time. For example, a class called SurveyAnswerStore uses one of two queues, depending on whether the tenant is a premium or standard tenant. A simple approach is to use Unity to resolve both queue types as shown in the following sample.

public class SurveyAnswerStore : ISurveyAnswerStore
{
  ...
  private readonly IMessageQueue<SurveyAnswerStoredMessage>
    standardSurveyAnswerStoredQueue;
  private readonly IMessageQueue<SurveyAnswerStoredMessage>
    premiumSurveyAnswerStoredQueue;

  public SurveyAnswerStore(
  ITenantStore tenantStore, 
  ISurveyAnswerContainerFactory surveyAnswerContainerFactory,
  IMessageQueue<SurveyAnswerStoredMessage> standardSurveyAnswerStoredQueue, 
  IMessageQueue<SurveyAnswerStoredMessage> premiumSurveyAnswerStoredQueue, 
  IBlobContainer<List<string>> surveyAnswerIdsListContainer)
  {
    ...
    this.standardSurveyAnswerStoredQueue = standardSurveyAnswerStoredQueue;
    this.premiumSurveyAnswerStoredQueue = premiumSurveyAnswerStoredQueue;
    
  }
  
  public void SaveSurveyAnswer(SurveyAnswer surveyAnswer)
  {
    var tenant = this.tenantStore.GetTenant(surveyAnswer.Tenant);
    ...

      (SubscriptionKind.Premium.Equals(tenant.SubscriptionKind)
      ? this.premiumSurveyAnswerStoredQueue
      : this.standardSurveyAnswerStoredQueue)
      .AddMessage(new SurveyAnswerStoredMessage
      {
        ...
      });    
  }
  ...
}

In this example, when the container resolves the SurveyAnswerStore type it will inject two IMessageQueue<SurveyAnswerStoredMessage> instances. If you know that only one of these instances will be used, you might consider optimizing the solution to create only the instance you need.

One approach is to write a factory class that will instantiate the correct instance, and then take a dependency on the factory. The following code sample shows this approach.

class SurveyAnswerStore : ISurveyAnswerStore

{
  ...
  private readonly ISurveyAnswerQueueFactory surveyAnswerQueueFactory;

  public SurveyAnswerStore(
  ITenantStore tenantStore, 
  ISurveyAnswerContainerFactory surveyAnswerContainerFactory,
  ISurveyAnswerQueueFactory surveyAnswerQueueFactory, 
  IBlobContainer<List<string>> surveyAnswerIdsListContainer)
  {
    ...
    this.surveyAnswerQueueFactory = surveyAnswerQueueFactory;
  }
  
  public void SaveSurveyAnswer(SurveyAnswer surveyAnswer)
  {
    var tenant = this.tenantStore.GetTenant(surveyAnswer.Tenant);
    ...

      ((tenant.SubscriptionKind == "Premium")
      ? this.surveyAnswerQueueFactory.GetPremiumQueue()
      : this.surveyAnswerQueueFactory.GetStandardQueue())
      .AddMessage(new SurveyAnswerStoredMessage
      {
        ...
      });    
  }
  ...
}

For this approach to work, in addition to writing the factory class, you must register the factory class with the container so that the container can inject it when it resolves the SurveyAnswerStore type.

A further refinement is to use Unity’s automatic factory approach. Using this approach you do not need to write and register a factory class, Unity creates a lightweight factory and registers it on your behalf. The following code sample shows this approach.

class SurveyAnswerStore : ISurveyAnswerStore

{
  ...
  private readonly Func<IMessageQueue<SurveyAnswerStoredMessage>>
    standardSurveyAnswerQueueFactory;
  private readonly Func<IMessageQueue<SurveyAnswerStoredMessage>>
    premiumSurveyAnswerQueueFactory;


  public SurveyAnswerStore(
  ITenantStore tenantStore, 
  ISurveyAnswerContainerFactory surveyAnswerContainerFactory,
  [Dependency("Standard")]Func<IMessageQueue<SurveyAnswerStoredMessage>>
    standardSurveyAnswerQueueFactory,
  [Dependency("Premium")]Func<IMessageQueue<SurveyAnswerStoredMessage>>
    premiumSurveyAnswerQueueFactory,
  IBlobContainer<List<string>> surveyAnswerIdsListContainer)
  {
    ...
    this.standardSurveyAnswerQueueFactory = standardSurveyAnswerQueueFactory;
    this.premiumSurveyAnswerQueueFactory = premiumSurveyAnswerQueueFactory;
  }
  public void SaveSurveyAnswer(SurveyAnswer surveyAnswer)
  {
    var tenant = this.tenantStore.GetTenant(surveyAnswer.Tenant);
    ...

      ((tenant.SubscriptionKind == "Premium")
      ? premiumSurveyAnswerQueueFactory()
      : standardSurveyAnswerQueueFactory())
      .AddMessage(new SurveyAnswerStoredMessage
      {
        ...
      });
  }
  ...
}

In this example, the dependencies of the SurveyAnswerStore class are on values of the form Func<T>. This enables the container to generate delegates that perform the type resolution when they are invoked: in the sample code, the delegates are called premiumSurveyAnswerQueueFactory and standardSurveyAnswerQueueFactory.

Dn178463.note(en-us,PandP.30).gifMarkus says:
Markus You don’t need to change the registrations in the container to make this approach work.

One drawback of this specific example is that because the two queues use named registrations in the container, you must use the Dependency attribute to specify which named registration to resolve. This means that the SurveyAnswerStore class has a dependency on Unity.

Deferred Resolution

Sometimes, you may want to resolve an object from the container, but defer the creation of the object until you need to use it. You can achieve this with Unity by using the Lazy<T> type from the .NET Framework; this type provides support for the lazy initialization of objects.

Dn178463.note(en-us,PandP.30).gifJana says:
Jana Lazy<T> doesn't work very well with value types, and it is better to avoid in this case. You should use the Lazy<T> type very cautiously.

To use this approach with Unity, you can register the type you want to use in the standard way, and then use the Lazy<T> type when you resolve it. The following code sample shows this approach.

// Register the type
container.RegisterType<MySampleObject>(new InjectionConstructor("default"));
 
// Resolve using Lazy<T>
var defaultLazy = container.Resolve<Lazy<MySampleObject>>();
 
// Use the resolved object
var mySampleObject = defaultLazy.Value;

This example is adapted from the sample application, “OtherUnitySamples,” included with this guidance.

You can use lazy resolution with the Unity lifetime managers. The following example, again adapted from the sample application illustrates this with the ContainerManagedLifetime class.

// Register the type with a lifetime manager
container.RegisterType<MySampleObject>(
  "other", new ContainerControlledLifetimeManager(),
  new InjectionConstructor("other"));
 
// Resolve the lazy type
var defaultLazy1 = container.Resolve<Lazy<MySampleObject>>("other");
 
// Resolve the lazy type a second time
var defaultLazy2 = container.Resolve<Lazy<MySampleObject>>("other");
 
// defaultLazy1 == defaultLazy2 is false
// defaultLazy1.Value == defaultLazy2.Value is true

For more information about Lazy<T>, see the topic Lazy<T> Class on MSDN.

You can also use the Resolve method to resolve registered types by using Func<T> in a similar way.

Lifetime Management

When you resolve an object that you registered using the RegisterType method, the container instantiates a new object when you call the Resolve method: the container does not hold a reference to the object. When you create a new instance using the RegisterInstance method, the container manages the object and holds a reference to it for the lifetime of the container.

Lifetime Managers manage the lifetimes of objects instantiated by the container. The default lifetime manager for the RegisterType method is the TransientLifetimeManager and the default lifetime manager for the RegisterInstance method is the ContainerControlledLifetimeManager. If you want the container to create or return a singleton instance of a type when you call the Resolve method, you can use the ContainerControlledLifetimeManager type when you register your type or instance. The following example shows how you could tell the container to create a singleton instance of the TenantStore.

container.RegisterType<ITenantStore, TenantStore>(
  new ContainerControlledLifetimeManager());

The first time that you resolve the ITenantStore type the container creates a new TenantStore object and keeps a reference to it. On subsequent times when you resolve the ITenantStore type, the container returns a reference to the TenantStore object that it created previously. Some lifetime managers, such as the ContainerControlledLifetimeManager, are used to dispose the created objects when the container is disposed.

Dn178463.note(en-us,PandP.30).gifJana says:
Jana Lifetime managers enable you to control for how long the objects created by the container should live in your application. You can override the default lifetime managers that the RegisterType and RegisterInstance methods use.

Unity includes five other lifetime managers, described in the following sections, that you can use to address specific scenarios in your applications.

Hierarchical Lifetime Management

This type of lifetime management is useful if you have a hierarchy of containers. Earlier in this chapter, you saw how to use child containers to manage alternative mappings for the same type. You can also use child containers to manage the lifetime of resolved objects. Figure 2 illustrates a scenario where you have created two child containers and registered a type using the ContainerControlledLifetimeManager type to create a singleton.

Figure 2 - Container hierarchy with ContainerControlledLifetimeManager lifetime manager

Figure 2 - Container hierarchy with ContainerControlledLifetimeManager lifetime manager

If the client object executes the following code that creates the containers, performs the registrations, and then resolves the types, the three variables (tenant1, tenant2, and tenant3) all refer to the same instance managed by the containers.

IUnityContainer container = new UnityContainer();
container.RegisterType<ITenantStore, TenantStore>(
  new ContainerControlledLifetimeManager());
IUnityContainer child1 = container.CreateChildContainer();
IUnityContainer child2 = container.CreateChildContainer();

var tenant1 = child1.Resolve<ITenantStore>();
var tenant2 = child2.Resolve<ITenantStore>();
var tenant3 = container.Resolve<ITenantStore>();

However, if you use the HierarchicalLifetimeManager type, the container resolves the object as shown in Figure 3.

Figure 3 - Container hierarchy with HierarchicalLifetimeManager lifetime manager

Figure 3 - Container hierarchy with HierarchicalLifetimeManager lifetime manager

If the client executes the following code, the three variables (tenant1, tenant2, and tenant3) each refer to different TenantStore instances.

IUnityContainer container = new UnityContainer();
container.RegisterType<ITenantStore, TenantStore>(
  new HierarchicalLifetimeManager());
IUnityContainer child1 = container.CreateChildContainer();
IUnityContainer child2 = container.CreateChildContainer();
var tenant1 = child1.Resolve<ITenantStore>();
var tenant2 = child2.Resolve<ITenantStore>();
var tenant3 = container.Resolve<ITenantStore>();

Although you register the type with the parent container, each child container now resolves its own instance. Each child container manages its own singleton instance of the TenantStore type; therefore, if you resolve the same type from container #1 a second time, the container returns a reference to the instance it created previously.

Dn178463.note(en-us,PandP.30).gifCarlos says:
Carlos This approach is useful in web applications where you want to register your types once, but then resolve separate instances for each client session. This assumes that it is possible, with your design, to map one child container to each session.

Per Resolve Lifetime Management

Figure 4 shows part of the dependency tree for an application: the SurveysController type depends on the SurveyStore and SurveyAnswerStore types, both the SurveyStore and SurveyAnswerStore types depend on the TenantStore type.

Figure 4 - Sample dependency tree

Figure 4 - Sample dependency tree

If you use the default TransientLifetimeManager class when you register the SurveysController type, then when you resolve the SurveysController type, the container builds the object graph shown in Figure 5.

Figure 5 - Object graph generated using TransientLifetimeManager lifetime manager

Figure 5 - Object graph generated using TransientLifetimeManager lifetime manager

However, if you use the PerResolveLifetimeManager class in place of the TransientLifetimeManager class, then the container builds the object graph shown in Figure 6. With the PerResolveLifetimeManager class, the container reuses any instances it resolves during a call to the Resolve method in any other types it resolves during the same call.

Figure 6 - Object graph generated using the PerResolveLifetimeManager class

Figure 6 - Object graph generated using the PerResolveLifetimeManager class

Externally Controlled Lifetime Management

If you resolve a type that was registered using the ContainerControlledLifetimeManager class, the container creates a singleton instance and holds a strong reference to it: this means that the instance lives at least as long as the container. However, if you use the ExternallyControlledLifetimeManager class, when you resolve the type, the container creates a singleton instance but holds only a weak reference to it. In this case, you can directly manage the lifetime of the object: because of the weak reference, you can dispose of the object when you no longer need it. This enables you to inject objects that are not owned by the container; for example you might need to inject objects whose lifetime is managed by ASP.NET into instances created by the container. Also, the ExternallyControlledLifetimeManager class does not dispose the instances it holds references to when the container is disposed.

Per Request Lifetime Management

This lifetime manager is only available for use in Web applications when you’ve added the “Unity bootstrapper for ASP.NET MVC” NuGet package to your project. The PerRequestLifetimeManager class enables the container to create new instances of registered types for each HTTP request in an ASP.NET MVC application or an ASP.NET Web API application. Each call to Resolve a type within the context of a single HTTP request will return the same instance: in effect, the Unity container creates singletons for registered types for the duration of the HTTP request.

Although the PerRequestLifetimeManager class works correctly and can help you to work with stateful or thread-unsafe dependencies within the scope of an HTTP request, it is generally not a good idea to use it if you can avoid it. Using this lifetime manager can lead to bad practices or hard to find bugs in the end user’s application code when used incorrectly. The dependencies you register with the Unity container should be stateless, and if you have a requirement to share common state between several objects during the lifetime of an HTTP request, then you can have a stateless service that explicitly stores and retrieves this state using the System.Web.HttpContext.Items collection of the System.Web.HttpContext.Current object.

Dn178463.note(en-us,PandP.30).gifJana says:
Jana Think carefully about the implications for state management in your application if you plan to use the PerRequestLifetimeManager lifetime manager class.

Per Thread Lifetime Management

The final lifetime manger included with Unity enables you to resolve instances on a per thread basis. All calls to the Resolve method from the same thread return the same instance.

For more information about Unity’s lifetime managers, see the topic Understanding Lifetime Managers.

Dependency Injection and Unit Testing

In Chapter 1, one of the motivations for adopting a loosely coupled design was that it facilitates unit testing. In the example used in this chapter, one of the types registered with the container is the TenantStore class. The following code sample shows an outline of this class.

public class TenantStore : ITenantStore
{
  ...

  public TenantStore(IBlobContainer<Tenant> tenantBlobContainer,
    IBlobContainer<byte[]> logosBlobContainer)
  {
    ...
  }


  public Tenant GetTenant(string tenant)
  {
    ...
  }

  public IEnumerable<string> GetTenantNames()
  {
    ...
  }

  public void SaveTenant(Tenant tenant)
  {
    ...
  }

  public void UploadLogo(string tenant, byte[] logo)
  {
    ...
  }
}

This class has dependencies on the IBlobContainer<Tenant> and IBlobContainer<byte[]> types which the container resolves when it instantiates a TenantStore object. However, to test this class in a unit test, you don’t want to have to create these blob containers: now it’s easy to replace them with mocks for the purpose of the tests. The following code sample shows some example tests.

[TestMethod]
public void GetTenantReturnsTenantFromBlobStorage()
{
  var mockTenantBlobContainer = new Mock<IBlobContainer<Tenant>>();
  var store = new TenantStore(mockTenantBlobContainer.Object, null);
  var tenant = new Tenant();
  mockTenantBlobContainer.Setup(c => c.Get("tenant")).Returns(tenant);

  var actualTenant = store.GetTenant("tenant");

  Assert.AreSame(tenant, actualTenant);
}

[TestMethod]
public void UploadLogoGetsTenantToUpdateFromContainer()
{
  var mockLogosBlobContainer = new Mock<IBlobContainer<byte[]>>();
  var mockTenantContainer = new Mock<IBlobContainer<Tenant>>();
  var store = new TenantStore(
    mockTenantContainer.Object, mockLogosBlobContainer.Object);
  mockTenantContainer.Setup(c => c.Get("tenant"))
    .Returns(new Tenant() { Name = "tenant" }).Verifiable();
  mockLogosBlobContainer.Setup(
    c => c.GetUri(It.IsAny<string>())).Returns(new Uri("http://bloburi"));

  store.UploadLogo("tenant", new byte[1]);

  mockTenantContainer.Verify();
}

These two example tests provide mock objects that implement the IBlobContainer<Tenant> and IBlobContainer<byte[]> interfaces when they create the TenantStore instances to test.

Note

These examples use the Moq mocking library to create the mock objects. For more information, see http://code.google.com/p/moq/. Moq is also available as a NuGet package.

Summary

In this chapter, you saw how to use the Unity container to add support for dependency injection to a real-world application and how you can use a Unity container to register types, resolve types at runtime, and manage the lifetime of the resolved objects. In addition to seeing how the Unity container made it possible to build the application's object graph at startup, you also saw how this approach facilitated designing and running unit tests.

Next Topic | Previous Topic | Home | Community