Registering Injected Parameter and Property Values

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
  • Injecting Arrays at Run Time
  • Summary of the InjectionMember Methods and Overloads
  • For More Information on InjectionMembers

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.

IUnityContainer container = new UnityContainer()
    .RegisterType<AType>(new InjectionConstructor());

AType aType = container.Resolve<AType>();
'Usage
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
  • Specify a Property for Injection
  • Specify a Method for Injection

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.

container.RegisterType<ILogger, TraceSourceLogger>(
            "UI",
            new InjectionConstructor("UI"));
'Usage

container.RegisterType(Of ILogger, TraceSourceLogger) _
         ("UI", New InjectionConstructor("UI"))
[InjectionConstructor]
public TraceSourceLogger(TraceSource traceSource)
{
    this.traceSource = traceSource;
}
'Usage
<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.

IUnityContainer container = new UnityContainer()
            .RegisterType<MyObject>(
                  new InjectionConstructor(someInt, someString, someDouble));
'Usage
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.

container.RegisterType<DriveController>(
          new InjectionProperty("MyProperty"));
'Usage
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."

int expectedInt = 8;
container.RegisterType<DriveController>(
new InjectionProperty("IntProperty", expectedInt));
'Usage
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.

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);
}
'Usage
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.

private ILogger logger;
[Dependency]
public ILogger Logger
{
  get { return logger; }
  set { logger = value; }
}
'Usage
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.

container.RegisterType<DriveController>(
           new InjectionMethod("InitializeMe", 42.0, 
           new ResolvedParameter(typeof(ILogger), "SpecialLogger")));
'Usage
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.

    container.Resolve<Cars>(new DependencyOverride(typeof(Type), new InjectionParameter(typeof(int))));
    
    'Usage
    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.

// 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"))));
'Usage
' 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.

class MyClass{
  public MyClass(ILogger[] myLogger) 
  { }
}
'Usage
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.

container.RegisterType<MyClass>(
  new InjectionConstructor(new ResolvedArrayParameter<ILogger>(myLogger)));
'Usage
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>().

ILogger logger2 = new SpecialLogger();
IUnityContainer container = new UnityContainer();
container.RegisterType<MyTypeArray>(new InjectionConstructor(
        new ResolvedArrayParameter(
              typeof(ILogger),
              new ResolvedParameter<ILogger>("log1"),
              typeof(ILogger), logger2)));
'Usage
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.

ILogger o1 = new MockLogger();
ILogger o2 = new SpecialLogger();
container.RegisterType<MyArrayType>(
                       new InjectionConstructor(typeof(ILogger[])));
'Usage
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: