Registering Injected Parameter and Property Values

Microsoft Enterprise Library 5.0

DropDown image DropDownHover image Collapse image Expand image CollapseAll image ExpandAll image Copy image CopyHover image

This topic explains how to configure a container to perform dependency injection at run time by using the RegisterType method overloads with the InjectionMembers parameter and avoid relying on annotating the classes to resolve with attributes. This topic includes information on configuring Unity to automatically populate constructor and method parameters and property values when it resolves instances of types.

This topic contains the following sections to explain the use of the InjectionMembers methods:

Registering Injection for Parameters, Properties, and Methods using InjectionMembers

The RegisterType overloads allow for configuring injection by accepting InjectionMembers. Include the InjectionConstructor, InjectionProperty, and InjectionMethod classes as a RegisterType parameter to provide dependency injection configuration in a container for InjectionMember objects.

The following example shows the general syntax for using an InjectionMember subclass, InjectionConstructor, with the RegisterType method. In this example the default constructor is called.

C# Copy Code
IUnityContainer container = new UnityContainer()
    .RegisterType<AType>(new InjectionConstructor());

AType aType = container.Resolve<AType>();
Visual Basic Copy Code
Dim container As IUnityContainer = New UnityContainer()_
    .RegisterType(Of AType)(New InjectionConstructor())

Dim aType As AType = container.Resolve(Of AType)()

You can also use attributes applied to target class members to instruct Unity to inject dependent objects. For more information, see Using Injection Attributes.

You can use the RegisterType overloads to do the following:

Register Constructors and Parameters

You can specify a constructor for the injection of a specific named instance. When you include a call to the InjectionConstructor method with a specific name, this provides the necessary information on which constructor to use and you do not need to call RegisterInstance. If you use the annotated constructor, you require a call to RegisterInstance.

In the following example, InjectionConstructor indicates which constructor to use based on its arguments, the string "UI," and causes the TraceSourceLogger constructor with a single string parameter to be invoked.

C# Copy Code
container.RegisterType<ILogger, TraceSourceLogger>(
            "UI",
            new InjectionConstructor("UI"));
Visual Basic Copy Code
container.RegisterType(Of ILogger, TraceSourceLogger) _
         ("UI", New InjectionConstructor("UI"))

C# Copy Code
[InjectionConstructor]
public TraceSourceLogger(TraceSource traceSource)
{
    this.traceSource = traceSource;
}
Visual Basic Copy Code
<InjectionConstructor> _
Public Sub New(traceSource As TraceSource)
Me.traceSource = traceSource
End Sub

Note:
InjectionConstructor() takes precedence over the constructor annotated with the InjectionConstructor attribute.


You could also use the InjectionConstructor method to configure the container to call the constructor with the provided values and build the instance instead of just registering an instance created elsewhere. The following example passes values to the constructor.

C# Copy Code
IUnityContainer container = new UnityContainer()
            .RegisterType<MyObject>(
                  new InjectionConstructor(someInt, someString, someDouble));
Visual Basic Copy Code
Dim container As IUnityContainer = New UnityContainer()
           .RegisterType(Of MyObject)
                  (New InjectionConstructor(someInt, someString, someDouble))

Note:
You could use constructor injection to specify any of a series of constructors or method overloads; however, you could inadvertently cause infinite recursion. To avoid the infinite recursion, specify which constructor to call in the RegisterType call. For more information see Circular References with Dependency Injection.

Specify a Property for Injection

You can configure the container to inject a property with or without a value for the property.

In the following example, property injection is configured for the property named MyProperty to use the default configuration of the container. The container resolves the value for this property using registrations and mappings within the container.

C# Copy Code
container.RegisterType<DriveController>(
          new InjectionProperty("MyProperty"));
Visual Basic Copy Code
container.RegisterType(Of DriveController) _
         (New InjectionProperty("MyProperty"))

The following example configures property injection for the property named IntProperty to use a specified value. The container sets the property to the value "8."

C# Copy Code
int expectedInt = 8;
container.RegisterType<DriveController>(
new InjectionProperty("IntProperty", expectedInt));
Visual Basic Copy Code
Dim expectedInt As Integer = 8
container.RegisterType(Of DriveController)(New InjectionProperty("IntProperty", expectedInt))

In the following example, the InjectionProperty object is configured, indicating that the property with the name Logger will be injected. Because there is no further configuration for this property, the unnamed instance for the property's type, ILogger, will be resolved when obtaining the value to inject to the property.

C# Copy Code
using (IUnityContainer container = new UnityContainer())
{
  container
    .RegisterType<IStocksTickerView, StocksTickerForm>()
    // Configure property injection.
    .RegisterType<IStockQuoteService, MoneyCentralStockQuoteService>(
                                      new InjectionProperty("Logger"))
    .RegisterType<ILogger, ConsoleLogger>()
    .RegisterType<ILogger, TraceSourceLogger>("UI")
    .RegisterInstance(new TraceSource("UI", SourceLevels.All));

  StocksTickerPresenter presenter = container.Resolve<StocksTickerPresenter>();

  Application.Run((Form)presenter.View);
}
Visual Basic Copy Code
Using container As IUnityContainer = New UnityContainer()
  container _
    .RegisterType(Of IStocksTickerView, StocksTickerForm)() _
    .RegisterType(Of IStockQuoteService, MoneyCentralStockQuoteService) _
                                         (New InjectionProperty("Logger")) _
    .RegisterType(Of ILogger, ConsoleLogger)() _
    .RegisterType(Of ILogger, TraceSourceLogger)("UI") _
    .RegisterInstance(New TraceSource("UI", SourceLevels.All))

  Dim presenter As StocksTickerPresenter = container.Resolve(Of StocksTickerPresenter)()

  Application.Run(DirectCast(presenter.View, Form))

End Using

Note:
This is similar to the use of the Dependency attribute without further configuration to annotate the property. Add the Dependency attribute to the Logger property, to indicate that the property should be injected with the result that the property's type, ILogger, is resolved in the container. The following example shows the comparable use of the Dependency attribute.


C# Copy Code
private ILogger logger;
[Dependency]
public ILogger Logger
{
  get { return logger; }
  set { logger = value; }
}
Visual Basic Copy Code
Private logger As ILogger
<Dependency> _
Public Property Logger() As ILogger
  Get
    Return logger
  End Get
  Set
    logger = value
  End Set
End Property

Specify a Method for Injection

You can configure a container to call methods during injection. The following example configures the method named InitializeMe for injection. It is configured with two parameters, a Double value and an instance of a class that implements the ILogger interface. It passes the value 42.0 to the first parameter and resolves the ILogger type through the container by looking for a mapping for that type with the name SpecialLogger and passes the result to the second parameter of the method.

C# Copy Code
container.RegisterType<DriveController>(
           new InjectionMethod("InitializeMe", 42.0, 
           new ResolvedParameter(typeof(ILogger), "SpecialLogger")));
Visual Basic Copy Code
container.RegisterType(Of DriveController)(_
        New InjectionMethod("InitializeMe", 42, _
        New ResolvedParameter(GetType(ILogger), "SpecialLogger")))

Injecting Arrays at Run Time

Although an array can be injected as a value by supplying it when configuring injection just as you would for any other CLR object, Unity enables you to configure array injection by using the result of resolving other keys as elements.

Unity provides API registration support for arrays by providing a resolver object that resolves all the named instances of the type registered in a container and an InjectionParameterValue that is used to configure parameters for constructor or method injection. The implementation for the ResolvedArray API support relies on the ResolveAll method in IUnityContainer. The ResolveAll method enables you to specify the type and returns all instances of all registered types requested even after you register multiple typenames of the same type.

The injection configuration APIs are based on the subclasses of InjectionParameterValue. You can also provide other types of objects when setting up injection. The objects are translated to a InjectionParameterValue according to the following rules:

  1. If the object is an instance of a subclass of the InjectionParameterValue class, the injection system uses the object.
  2. If the object is an instance of the Type class, the injection system creates a ResolvedParameter that describes how the container should perform injection to resolve an instance of that type.
    Note:
    In order to specify an instance of the Type class as a literal argument and ensure that the override is not resolved in the container as an instance of the specified type per this rule, you must inject an InjectionParameter with the Type object.

    C# Copy Code
    container.Resolve<Cars>(new DependencyOverride(typeof(Type), new InjectionParameter(typeof(int))));
    Visual Basic Copy Code
    container.Resolve(Of Cars)(New DependencyOverride(GetType(Type), _
            New InjectionParameter(GetType(Integer))))
  3. In all other cases, the configuration API creates an InjectionParameter instance the container uses to get the value to be injected into a property.
  4. You cannot supply null as the value to inject. You must explicitly provide an InjectionParameter, as with types.

Note:
The injection rules are located in the ToParameter method of the InjectionParameterValue class. You can examine this class to see the implementation. The InjectionConstructor, InjectionProperty, and InjectionMethod subclasses of the InjectionMember base class are used to describe the injection at the time the BuildPlan for a key is created. The BuildPlan is created the first time a key is resolved. After that, injection does not use these three subclasses. You can create your own subclasses based on this class if you want to extend or change the behavior to suit your own specific requirements. You can also create your own subclasses based on the InjectionParameterValue class if you want to customize the handling of individual parameters.


There are two kinds of array injection in Unity:

  • Injecting an array that contains all the instances of the array's element type registered in the container (in the order they were registered).
    Note:
    This is comparable to using the <dependency> or <optional> element in the configuration. Attribute support for injecting all registered members of an array is provided by using the [Dependency] attribute. Using the [Dependency] attribute produces the equivalent results for injection. You can also use the [OptionalDependency] attribute just like you use the Dependency attribute only it is for optional dependencies.

  • Injecting an array containing the result of resolving a specific key by using ResolvedArrayParameter. There is no attribute support in this case. Use InjectionParameterValues to specify how each element in the array should be resolved.
    Note:
    Using ResolvedArrayParameter is comparable to using or the <array> element in the configuration file where you would use the <array> element to specify how each element should be resolved.

Injection of properties can be specified simultaneously in the configuration file and through code. The injection specification using the API overrides any previous specification from the configuration file, but non-overlapping definitions will be observed regardless of their origin because the underlying mechanism is the same. Injection of properties indicated through attributes in the resolved types is observed only when there are no other injection specifications for any property in the same type.

Injecting Specific Array Instances

The ResolvedArrayParameter works like any other InjectionParameterValue used to specify how to supply a constructor argument or a property value. In the following example the ILogger[] parameter is injected with a two-element array based on the two arguments for ResolvedArrayParameter. The first element is the result of resolving the ILogger interface without a name per the typeof(ILogger) argument.


Note:
typeof(ILogger) is equivalent to new ResolvedParameter<ILogger>().


The second element is the result of resolving the ILogger interface with the UI name per the new ResolvedParameter<ILogger>("UI") argument expression. When using this kind of array injection, literal values can be specified as members of the array and as unnamed instances.

C# Copy Code
// Map the ILogger interface to the CompositeLogger class to inject 
// an array of specific instances through the constructor.
container.RegisterType<ILogger, CompositeLogger>(
  "composite", 
  new InjectionConstructor(
    new ResolvedArrayParameter<ILogger>(
        typeof(ILogger),
        new ResolvedParameter<ILogger>("UI"))));
Visual Basic Copy Code
' Map the ILogger interface to the CompositeLogger class to inject 
' an array of specific instances through the constructor.
container.RegisterType(Of ILogger, CompositeLogger)( _
  "composite", _
  New InjectionConstructor( _
    New ResolvedArrayParameter(Of ILogger)( _
        GetType(ILogger), _
        New ResolvedParameter(Of ILogger)("UI"))))

The following example shows how to inject a specific instance of an array. Start with the class MyClass with a member, myLogger, which is an ILogger array.

C# Copy Code
class MyClass{
  public MyClass(ILogger[] myLogger) 
  { }
}
Visual Basic Copy Code
Class MyClass
  Public  Sub New(ByVal myLogger() As ILogger)
  End Sub
End Class

The following example code injects a specific instance, myLogger, of an array, ILogger, into MyClass.

C# Copy Code
container.RegisterType<MyClass>(
  new InjectionConstructor(new ResolvedArrayParameter<ILogger>(myLogger)));
Visual Basic Copy Code
container.RegisterType(MyClass)( _
  New InjectionConstructor(New ResolvedArrayParameter(Of ILogger)(myLogger)))

By using ResolvedArrayParameter as a constructor parameter you will get the registered instances of the specified array, myLogger. At resolve time, the container calls ResolveAll<ILogger> and injects the resulting array into the constructor.

The following example configures the container to inject specific array values, log1 and logger2. ResolvedArrayParameter supplies the InjectionConstructor constructor argument. typeof(ILogger) is shorthand for newResolvedParameter<ILogger>().

C# Copy Code
ILogger logger2 = new SpecialLogger();
IUnityContainer container = new UnityContainer();
container.RegisterType<MyTypeArray>(new InjectionConstructor(
        new ResolvedArrayParameter(
              typeof(ILogger),
              new ResolvedParameter<ILogger>("log1"),
              typeof(ILogger), logger2)));
Visual Basic Copy Code
Dim logger2 As ILogger = New SpecialLogger()
Dim container As IUnityContainer = New UnityContainer()
container.RegisterType(Of MyTypeArray) (New InjectionConstructor( _
        New ResolvedArrayParameter( _
            GetType(ILogger), _
            New ResolvedParameter(Of ILogger)("log1"), _
            GetType(ILogger), logger2)))

Injecting All Array Named Instances

The following example configures the container to call the constructor with an array parameter. The entire array will be injected.

C# Copy Code
ILogger o1 = new MockLogger();
ILogger o2 = new SpecialLogger();
container.RegisterType<MyArrayType>(
                       new InjectionConstructor(typeof(ILogger[])));
Visual Basic Copy Code
Dim o1 As ILogger =  New MockLogger() 
Dim o2 As ILogger =  New SpecialLogger() 
container.RegisterType(Of MyArrayType)( _
                       New InjectionConstructor(GetType(ILogger())))

Summary of the InjectionMember Methods and Overloads

The RegisterType method overloads take an optional InjectionMember parameter. For the table of RegisterType method overloads see the "Summary of the RegisterType Method Overloads" table in the Registering Types and Type Mappings topic.

The following table summarizes the InjectionMembers methods used in RegisterType method overloads that allow for configuring injection of parameters, properties, and methods. You can use these to register the information required for injecting types and values into constructor and method parameters and properties at run time.

Method

Description

RegisterType(Type from, Type to, string name, LifetimeManager lifetimeManager,

params InjectionMember[] injectionMembers);

General form for using the RegisterType method. Registers a type mapping with the container so that it returns an instance of the type specified as to when a Resolve method requests an instance of the type from with the specified name, null if a default registration,

The lifetimeManager controls the lifetime of the returned instance. Objects configured to get injected by the container are specified by injectionMembers.

RegisterType<AType>(new InjectionConstructor())

Creates a new instance of InjectionConstructor that uses the default constructor.

RegisterType<AType>(new InjectionConstructor(params object[] parameterValues))

Creates a new instance of InjectionConstructor that looks for a constructor with the given set of parameters.

parameterValues: The values for the parameters.

RegisterType<AType>(new InjectionProperty(string propertyName))

Configures the container to inject the given property name, resolving the value via the container. The propertyName parameter is the name of the property to inject.

RegisterType<AType>(new InjectionProperty((string propertyName, object propertyValue))

Configures the container to inject the given property name, using the value supplied. The propertyName parameter is the name of the property to inject. The propertyValue parameter is the value for the property.

RegisterType<AType>(new InjectionParameter(object parameterValue))

Creates an instance of InjectionParameter that stores the given value, using the runtime type of that value as the type of the parameter.

RegisterType<AType>(new InjectionParameter(System.Type parameterType, object parameterValue))

Creates an instance of InjectionParameter that stores the given value, associated with the given type.

parameterType: Type of the parameter.

parameterValue: Value of the parameter

RegisterType<AType>(new InjectionParameter<TParameter>)

A generic version of Microsoft.Practices.Unity.InjectionParameter. Creates a new InjectionParameter<TParameter>. TParameter = value for the parameter.

RegisterType<AType>(new InjectionMethod(string methodName, params object[] methodParameters)

Configures the container to call the given methods with the given parameters.

methodName: Name of the method to call.

methodParameters: Parameter values for the method.

More Information

For more information about the techniques discussed in this topic, see the following topics: