Chapter 5. The IoC container

5.1. Introduction

This chapter covers the Spring Framework's implementation of the Inversion of Control (IoC) [1] principle

The Spring.Core assembly provides the basis for the Spring.NET Inversion of Control container. The IObjectFactory interface provides an advanced configuration mechanism capable of managing objects of any nature. The IApplicationContext interface builds on top of the IObjectFactory (it is a sub-interface) and adds other functionality such as easier integration with Spring.NET's Aspect Oriented Programming (AOP) features, message resource handling (for use in internationalization), event propagation and application layer-specific context such as WebApplicationContext for use in web applications.

In short, the IObjectFactory provides the configuration framework and basic functionality, while the IApplicationContext adds more enterprise-centric functionality to it. The IApplicationContext is a complete superset of the IObjectFactory, and any description of IObjectFactory capabilities and behavior should be considered to apply to IApplicationContexts as well.

This chapter is divided into two parts, with the first part covering the basic principles that apply to both the IObjectFactory and IApplicationContext, with the second part covering those features that apply only to the IApplicationContext interface.

If you are new to Spring.NET or IoC containers in general, you may want to consider starting with Chapter 33, IoC Quickstarts, which contains a number of introductory level examples that actually demonstrate a lot of what is described in detail below. Don't worry if you don't absorb everything at once... those examples serve only to paint a picture of how Spring.NET hangs together in really broad brushstrokes. Once you have finished with those examples, you can come back to this section which will fill in all the fine detail.

5.2. Basics - containers and objects

5.2.1. The container

The IObjectFactory is the actual representation of the Spring IoC container that is responsible for instantiating, configuring, and managing a number of objects.

The IObjectFactory interface is the central IoC container interface in Spring. Its responsibilities include instantiating or sourcing application objects, configuring such objects, and assembling the dependencies between these objects.

There are a number of implementations of the IObjectFactory interface that come supplied straight out-of-the-box with Spring. The most commonly used IObjectFactory implementation is the XmlObjectFactory class. This implementation allows you to express the objects that compose your application, and the doubtless rich interdependencies between such objects, in terms of XML. The XmlObjectFactory takes this XML configuration metadata and uses it to create a fully configured system or application. Interaction with the IObjectFactory interface is discussed in Section 5.2.6, “Using the container”. Additional features offered by another implementation of IObjectFactory, the IApplicationContext, are discussed in section Section 5.10, “The IApplicationContext.

5.2.1.1. Configuration metadata

As can be seen in the above image, the Spring IoC container consumes some form of configuration metadata; this configuration metadata is nothing more than how you (as an application developer) inform the Spring container as to how to “instantiate, configure, and assemble [the objects in your application]”. This configuration metadata is typically supplied in a simple and intuitive XML format. When using XML-based configuration metadata, you write object definitions for those object that you want the Spring IoC container to manage, and then let the container do it's stuff.

[Note]Note

XML-based metadata is by far the most commonly used form of configuration metadata. It is not however the only form of configuration metadata that is allowed. The Spring IoC container itself is totally decoupled from the format in which this configuration metadata is actually written. Attribute based metadata will be part of an upcoming release and it is already part of the Spring Java framework.

Spring configuration consists of at least one object definition that the container must manage, but typically there will be more than one object definition. When using XML-based configuration metadata, these object are configured as <object/> elements inside a top-level <objects/> element.

These object definitions correspond to the actual objects that make up your application. Typically you will have object definitions for your service layer objects, your data access objects (DAOs), presentation objects such as ASP.NET page instances, infrastructure objects such as NHibernate SessionFactories, and so forth. Typically one does not configure fine-grained domain objects in the container, because it is usually the responsibility of DAOs and business logic to create/load domain objects.

Find below an example of the basic structure of XML-based configuration metadata.

<objects xmlns="http://www.springframework.net">

  <object id="..." type="...">
    <!-- collaborators and configuration for this object go here -->
  </object>

  <object id="...." type="...">
    <!-- collaborators and configuration for this object go here -->
  </object>
 
  <!-- more object definitions go here -->

</objects>

5.2.2. Instantiating a container

Instantiating a Spring IoC container is straightforward.

IApplicationContext context = new XmlApplicationContext(
                 "file://services.xml",
                 "assembly://MyAssembly/MyDataAccess/data-access.xml");

// an IApplicationContext is also an IObjectFactory (via inheritance)
IObjectFactory factory = context;

You can also create an container by using a custom configuration section in the standard .NET application (or web) configuration file. Once the container has been created you may never need to explicitly interact with it again in your code, for example when configuring ASP.NET pages.

You may be wondering what the assembly URL is all about. The above example uses Spring.NET's IResource abstraction. The IResource interface provides a simple and uniform interface to a wide array of IO resources that can represent themselves as System.IO.Stream. An example for a file based resource, not using the URL syntax but an implementation of the IResource interface for file is shown below.

[C#]
IResource input = new FileSystemResource ("objects.xml");
IObjectFactory factory = new XmlObjectFactory(input);

These resources are most frequently files or URLs but can also be resources that have been embedded inside a .NET assembly. A simple URI syntax is used to describe the location of the resource, which follows the standard conventions for files, i.e. file://object.xml and other well known protocols such as http.

The following snippet shows the use of the URI syntax for referring to a resource that has been embedded inside a .NET assembly, assembly://<AssemblyName>/<NameSpace>/<ResourceName>

[Note]Note
To create an embedded resource using Visual Studio you must set the Build Action of the .xml configuration file to Embedded Resource in the file property editor. Also, you will need to explicitly rebuild the project containing the configuration file if it is the only change you make between successive builds. If using NAnt to build, add a <resources> section to the csc task. For example usage, look at the Spring.Core.Tests.build file included the distribution.

The IResource abstraction is explained further in Section 7.1, “Introduction”.

The preferred way to create an IApplicationContext or IObjectFactory is to use a custom configuration section in the standard .NET application configuration file (one of App.config or Web.config). A custom configuration section that creates the same IApplicationContext as the previous example is

<spring>
  <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
    <resource uri="file://services.xml"/>
    <resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/>
  </context>
</spring>

The context type (specified as the value of the type attribute of the context element) is wholly optional, and defaults to the Spring.Context.Support.XmlApplicationContext class, so the following XML snippet is functionally equivalent to the first.

<spring>
  <context>
    <resource uri="file://services.xml"/>
    <resource uri="assembly://MyAssembly/MyDataAccess/data-access.xml"/>
  </context>
</spring> 

To acquire a reference to an IApplicationContext using a custom configuration section, one simply uses the following code;

IApplicationContext ctx = ContextRegistry.GetContext();

The ContextRegistry is used to both instantiate the application context and to perform service locator style access to other objects. (See Section 5.15, “Service Locator access” for more information). The glue that makes this possible is an implementation of the Base Class Library (BCL) provided IConfigurationSectionHandler interface, namely the Spring.Context.Support.ContextHandler class. The handler class needs to be registered in the configSections section of the .NET configuration file as shown below.

<configSections>
  <sectionGroup name="spring">
    <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
  </sectionGroup>
</configSections> 

This declaration now enables the use of a custom context section starting at the spring root element.

In some usage scenarios, user code will not have to explicitly instantiate an appropriate implementation of the IObjectFactory interface, since Spring.NET code will do it. For example, the ASP.NET web layer provides support code to load a Spring.NET IApplicationContext automatically as part of the normal startup process of an ASP.NET web application. Similar support for WinForms applications is being investigated.

While programmatic manipulation of IObjectFactory instances will be described later, the following sections will concentrate on describing the configuration of objects managed by IObjectFactory instances.

Spring.NET comes with an XSD schema to make the validation of the XML object definitions a whole lot easier. The XSD document is thoroughly documented so feel free to take a peek inside (see Appendix C, Spring.NET's spring-objects.xsd). The XSD is currently used in the implementation code to validate the XML document. The XSD schema serves a dual purpose in that it also facilitates the editing of XML object definitions inside an XSD aware editor (typically Visual Studio) by providing validation (and Intellisense support in the case of Visual Studio). You may wish to refer to Chapter 32, Visual Studio.NET Integration for more information regarding such integration.

Your XML object definitions can also be defined within the standard .NET application configuration file by registering the Spring.Context.Support.DefaultSectionHandler class as the configuration section handler for inline object definitions. This allows you to completely configure one or more IApplicationContext instances within a single standard .NET application configuration file as shown in the following example.

<configuration>

  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
    </sectionGroup>
  </configSections>

  <spring>

    <context>
      <resource uri="config://spring/objects"/>
    </context>
       
    <objects xmlns="http://www.springframework.net">
        ...
    </objects>

  </spring>

</configuration>

Other options available to structure the configuration files are described in Section 5.12.1, “Context Hierarchies” and ???.

The IApplicationContext can be configured to register other resource handlers, custom parsers to integrate user-contributed XML schema into the object definitions section, type converters, and define type aliases. These features are discussed in section Section 5.11, “Configuration of IApplicationContext”

5.2.2.1. Composing XML-based configuration metadata

It is often useful to split up container definitions into multiple XML files. One way to then load an application context which is configured from all these XML fragments is to use the application context constructor which takes multiple resource locations. With an object factory, an object definition reader can be used multiple times to read definitions from each file in turn.

Generally, the Spring.NET team prefers the above approach, assembling individual files because it keeps container configuration files unaware of the fact that they are being combined with others. However, an alternate approach is to compose one XML object definition file using one or more occurrences of the import element to load definitions from other files. Any import elements must be placed before object elements in the file doing the importing. Let's look at a sample:

<objects xmlns="http://www.springframework.net">

  <import resource="services.xml"/>
  <import resource="resources/messageSource.xml"/>
  <import resource="/resources/themeSource.xml"/>

  <object id="object1" type="..."/>
  <object id="object2" type="..."/>

</objects>

In this example, external object definitions are being loaded from 3 files, services.xml, messageSource.xml, and themeSource.xml. All location paths are considered relative to the definition file doing the importing, so services.xml in this case must be in the same directory as the file doing the importing, while messageSource.xml and themeSource.xml must be in a resources location below the location of the importing file. As you can see, a leading slash is actually ignored, but given that these are considered relative paths, it is probably better form not to use the slash at all. The contents of the files being imported must be fully valid XML object definition files according to the XSD, including the top level objects element.

5.2.3. The Objects

A Spring IoC container manages one or more objects. these objects are created using the configuration metadata that has been supplied to the container (typically in the form of XML <object/> definitions).

Within the container itself, these object definitions are represented as IObjectDefinition objects, which contain (among other information) the following metadata:

  • A type name: typically this is the actual implementation class of the object being defined..

  • Object behavioral configuration elements, which state how the object should behave in the Spring.NET IoC container (i.e. prototype or singleton, lifecycle callbacks, and so forth)

  • references to other objects which are needed for the object to do its work: these references are also called collaborators or dependencies.

  • other configuration settings to set in the newly created object. An example would be the number of threads to use in an object that manages a worker thread pool, or the size limit of the pool.

The concepts listed above directly translate to a set of elements the object definition consists of. These elements are listed below, along with a link to further documentation about each of them.

Table 5.1. Object definition explanation


Besides object definitions which contain information on how to create a specific object, certain IObjectFactory implementations also permit the registration of existing objects that have been created outside the factory (by user code). The DefaultListableObjectFactory class supports this through the RegisterSingleton(..) method. (Typical applications solely work with objects defined through metadata object definitions though.)

5.2.3.1. Naming objects

Every object has one or more ids (also called identifiers, or names; these terms refer to the same thing). These ids must be unique within the container the object is hosted in. An object will almost always have only one id, but if an object has more than one id, the extra ones can essentially be considered aliases.

When using XML-based configuration metadata, you use the 'id' or 'name'attributes to specify the object identifier(s). The 'id' attribute allows you to specify exactly one id, and as it is a real XML element ID attribute, the XML parser is able to do some extra validation when other elements reference the id; as such, it is the preferred way to specify an object id. However, the XML specification does limit the characters which are legal in XML IDs. This is usually not a constraint, but if you have a need to use one of these special XML characters, or want to introduce other aliases to the object, you may also or instead specify one or more object ids, separated by a comma (,), semicolon (;), or whitespace in the 'name' attribute.

Please note that you are not required to supply a name for a object. If no name is supplied explicitly, the container will generate a unique name for that object. The motivations for not supplying a name for a object will be discussed later (one use case is inner objects).

5.2.3.1.1. Aliasing objects

In an object definition itself, you may supply more than one name for the object, by using a combination of the id and name attributes as discussed in ???. This approach to aliasing objects has some limitations when you would like to assemble the main application configuration file from multiple files. See ??? for more information. This usage pattern is common when each configuration file represents a logical layer or component within the application. In this case you may want to refer to a common object dependency using a name that is specific to each file. If the common object dependency is defined in the main application configuration file itself, then one can use the name element as an alias mechanism. However, if the main application configuration file should not be responsible for defining the common object dependency, since it logically 'belongs' to one of the other layers or components, you can not use the name attribute to achieve this goal.

In this case, you can define an alias using an explicit alias element contained in the main application configuration file.

<alias name="fromName" alias="toName"/>

This allows an object named fromName to be referred to as toName across all application configuration files.

As a concrete example, consider the case where the configuration file 'a.xml' (representing component A) defines a connection object called componentA-connection. In another file, 'b.xml' (representing component B) would like to refer to the connection as componentB-connection. And the main application, MyApp, defines its own XML fragment to assembles the final application configuration from all three fragments and would like to refer to the connection as myApp-connection. This scenario can be easily handled by adding to the MyApp XML fragment the following standalone aliases:

<alias name="componentA-connection" alias="componentB-connection"/>

<alias name="componentA-connection" alias="myApp-connection"/>

Now each component and the main app can refer to the connection via a name that is unique and guaranteed not to clash with any other definition (effectively there is a namespace), yet they refer to the same object.

5.2.4. Object creation

An object definition essentially is a recipe for creating one or more objects. The container looks at the recipe for a named object when asked, and uses the configuration metadata encapsulated by that object definition to create (or acquire) an actual object.

If you are using XML-based configuration metadata, you can specify the type of object that is to be instantiated using the 'type' attribute of the <object/> element. This 'type' attribute (which internally eventually boils down to being a Type property on a IObjectDefinition instance) is normally mandatory (see XXX “Instantiation using an instance factory method” and XXX “Object definition inheritance” for the two exceptions) and is used for one of two purposes. The type property specifies the type of of the object to be constructed in the common case where the container itself directly creates the object by calling its constructor reflectively (somewhat equivalent to C# code using the 'new' operator). In the less common case where the container invokes a static, factory method on a class to create the object, the type property specifies the actual class containing the static factory method that is to be invoked to create the object (the type of the object returned from the invocation of the static factory method may be the same type or another type entirely, it doesn't matter).

5.2.4.1. Object creation via constructor invocation

When creating an object using the constructor approach, all normal classes are usable by and compatible with Spring. That is, the type being created does not need to implement any specific interfaces or be coded in a specific fashion. Just specifying the object type should be enough. However, depending on what type of IoC you are going to use for that specific object, you may need to create a default constructor (i.e. a constructor that has no parameters) in the source code definition of your class.

The XmlObjectFactory implementation of the IObjectFactory interface can consume object definitions that have been defined in XML, for example...

<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary"/>

The mechanism for supplying arguments to the constructor (if required), or setting properties of the object instance after it has been constructed, is described shortly.

This XML fragment describes an object definition that will be identified by the exampleObject name, instances of which will be of the Examples.ExampleObject type that has been compiled into the ExamplesLibrary assembly. Take special note of the structure of the type attribute's value... the namespace-qualified name of the class is specified, followed by a comma, followed by (at a bare minimum) the name of the assembly that contains the class. In the preceding example, the ExampleObject class is defined in the Examples namespace, and it has been compiled into the ExamplesLibrary assembly.

The name of the assembly that contains the type must be specified in the type attribute. Furthermore, it is recommended that you specify the fully qualified assembly name [2] in order to guarantee that the type that Spring.NET uses to instantiate your object (s) is indeed the one that you expect. Usually this is only an issue if you are using classes from (strongly named) assemblies that have been installed into the Global Assembly Cache (GAC).

If you have defined nested classes use the addition symbol, +, to reference the nested class. For example, if the class Examples.ExampleObject had a nested class Person the XML declaration would be

<object id="exampleObject" type="Examples.ExampleObject+Person, ExamplesLibrary"/>

If you are defining classes that have been compiled into assemblies that are available to your application (such as the bin directory in the case of ASP.NET applications) via the standard assembly probing mechanisms, then you can specify simply the name of the assembly (e.g. ExamplesLibrary.Data)... this way, when (or if) the assemblies used by your application are updated, you won't have to change the value of every <object/> definition's type attribute to reflect the new version number (if the version number has changed)... Spring.NET will automatically locate and use the newer versions of your assemblies (and their attendant classes) from that point forward.

5.2.4.2. Object creation via a static factory method

When defining an object which is to be created using a static factory method, along with the type attribute which specifies the type containing the static factory method, another attribute named factory-method is needed to specify the name of the factory method itself. Spring.NET expects to be able to call this method (with an optional list of arguments as described later) and get back a live object, which from that point on is treated as if it had been created normally via a constructor. One use for such an object definition is to call static factories in legacy code.

Following is an example of an object definition which specifies that the object is to be created by calling a factory-method. Note that the definition does not specify the type (class) of the returned object, only the type containing the factory method. In this example, CreateInstance must be a static method.

<object id="exampleObject"
      type="Examples.ExampleObjectFactory, ExamplesLibrary"
      factory-method="CreateInstance"/>

The mechanism for supplying (optional) arguments to the factory method, or setting properties of the object instance after it has been returned from the factory, will be described shortly.

5.2.4.3. Object creation via an instance factory method

In a fashion similar to instantiation using a static factory method, instantiation using an instance factory method is where a non-static method of an existing object from the container is invoked to create the new object. To use this mechanism, the 'type' attribute must be left empty, and the 'factory-object' attribute must specify the name of an object in the current (or parent/ancestor) container that contains the instance method that is to be invoked to create the object. The name of the factory method itself should still be set via the 'factory-method' attribute.

<!-- the factory object, which contains an instance method called 'CreateInstance' -->
<object id="exampleFactory" type="...">
  <!-- inject any dependencies required by this object -->
</object>

<!-- the object that is to be created by the factory object -->
<object id="exampleObject"
      factory-method="CreateInstance"
      factory-object="exampleFactory"/>

Although the mechanisms for setting object properties are still to be discussed, one implication of this approach is that the factory object itself can be managed and configured via Dependency Injection, by the container.

[Note]Note

When the Spring documentation makes mention of a 'factory object', this will be a reference to an object that is configured in the Spring container that will create objects via an instance or static factory method. When the documentation mentions a IFactoryObject (notice the capitalization) this is a reference to a Spring-specific IFactoryObject .

5.2.5. Object creation of generic types

Generic types can also be created in much the same manner an non-generic types.

5.2.5.1. Object creation of generic types via constructor invocation

The following examples shows the definition of simple generic types and how they can be created in Spring's XML based configuration file.

namespace GenericsPlay
{
    public class FilterableList<T>
    {
        private List<T> list;
        
        private String name;

        public List<T> Contents
        {
            get { return list; }
            set { list = value; }
        }

        public String Name
        {
            get { return name; }
            set { name = value; }
        }
        
        public List<T> ApplyFilter(string filterExpression)
        {
            /// should really apply filter to list ;)
            return new List<T>();
        }

    }
}

The XML configuration to create and configure this object is shown below

<object id="myFilteredIntList" type="GenericsPlay.FilterableList&lt;int>, GenericsPlay">
  <property name="Name" value="My Integer List"/>
</object>

There are a few items to note in terms how to specify a generic type. First, the left bracket that specifies the generic type, i.e. <, is replaced with the string &lt; due to XML escape syntax for the less than symbol. Yes, we all realize this is less than ideal from the readability point of view. Second, the generic type arguments can not be fully assembly qualified as the comma is used to separate generic type arguments. Alternative characters used to overcome the two quirks can be implemented in the future but so far, all proposals don't seem to help clarify the text. The suggested solution to improve readability is to use type aliases as shown below

<typeAliases>
 <alias name="GenericDictionary" type=" System.Collections.Generic.Dictionary&lt;,>" />
 <alias name="myDictionary" type="System.Collections.Generic.Dictionary&lt;int,string>" />
</typeAliases>

So that instead of something like this

<object id="myGenericObject" 
        type="GenericsPlay.ExampleGenericObject&lt;System.Collections.Generic.Dictionary&lt;int , string>>, GenericsPlay" />

It can be shortened to

<object id="myOtherGenericObject" 
        type="GenericsPlay.ExampleGenericObject&lt;GenericDictionary&lt;int , string>>, GenericsPlay" />

or even shorter

<object id="myOtherOtherGenericObject" 
        type="GenericsPlay.ExampleGenericObject&lt;MyIntStringDictionary>, GenericsPlay" />

Refer to Section 5.11, “Configuration of IApplicationContext” for additional information on using type aliases.

5.2.5.2. Object creation of generic types via static factory method

The following classes are used to demonstrate the ability to create instances of generic types that themselves are created via a static generic factory method.

public class TestGenericObject<T, U>
{
    public TestGenericObject()
    {
    }

    private IList<T> someGenericList = new List<T>();
    
    private IDictionary<string, U> someStringKeyedDictionary =
        new Dictionary<string, U>();

    public IList<T> SomeGenericList
    {
        get { return someGenericList; }
        set { someGenericList = value; }
    }

    public IDictionary<string, U> SomeStringKeyedDictionary
    {
        get { return someStringKeyedDictionary; }
        set { someStringKeyedDictionary = value; }
    }

}

The accompanying factory class is

public class TestGenericObjectFactory
{
    public static TestGenericObject<V, W> StaticCreateInstance<V, W>()
    {
        return new TestGenericObject<V, W>();
    }

    public TestGenericObject<V, W> CreateInstance<V, W>()
    {
        return new TestGenericObject<V, W>();
    }
}

The XML snippet to create an instance of TestGenericObject where V is a List of integers and W is an integer is shown below

<object id="myTestGenericObject"
        type="GenericsPlay.TestGenericObjectFactory, GenericsPlay"
        factory-method="StaticCreateInstance&lt;System.Collections.Generic.List&lt;int>,int>"
/>

The StaticCreateInstance method is responsible for instantiating the object that will be associated with the id 'myTestGenericObject'.

5.2.5.3. Object creation of generic types via instance factory method

Using the class from the previous example the XML snippet to create an instance of a generic type via an instance factory method is shown below

<object id="exampleFactory" type="GenericsPlay.TestGenericObject&lt;int,string>, GenericsPlay"/>

<object id="anotherTestGenericObject"
        factory-object="exampleFactory" 
        factory-method="CreateInstance&lt;System.Collections.Generic.List&lt;int>,int>"/>

This creates an instance of TestGenericObject<List<int>,int>

5.2.6. Using the container

An IApplicationContext is essentially nothing more than the interface for an advanced factory capable of maintaining a registry of different objects and their dependencies. The IApplicationContext enables you to read object definitions and access them. You create one and read in some object definition in the XML format as follows:

IApplicationContext context = new XmlApplicationContext("file://objects.xml");

Basically that is all there is to it. Using GetObject(string) or the indexer [string], you can retrieve instances of your object; the client-side view of the IApplicationContext is simple. The IApplicationContext interface has just a few other methods related to finding objects in the contianer, but ideally your application code should never use them... indeed, your application code should have no calls to the GetObject(string) method at all, and thus no dependency on Spring APIs at all.

5.3. Dependencies

Your typical enterprise application is not made up of a single object. Even the simplest of applications will no doubt have at least a handful of objects that work together to present what the end-user sees as a coherent application. This next section explains how you go from defining a number of object definitions that stand-alone, each to themselves, to a fully realized application where objects work (or collaborate) together to achieve some goal (usually an application that does what the end-user wants).

5.3.1. Injecting dependencies

The basic principle behind Dependency Injection (DI) is that objects define their dependencies (that is to say the other objects they work with) only through constructor arguments, arguments to a factory method, or properties which are set on the object instance after it has been constructed or returned from a factory method. Then, it is the job of the container to actually inject those dependencies when it creates the object. This is fundamentally the inverse, hence the name Inversion of Control (IoC), of the object itself being in control of instantiating or locating its dependencies on its own using direct construction of classes, or something like the Service Locator pattern.

It becomes evident upon usage that code gets much cleaner when the DI principle is applied, and reaching a higher grade of decoupling is much easier when objects do not look up their dependencies, but are provided with them (and additionally do not even know where the dependencies are located and of what concrete class they are). DI exists in two major variants, namely Constructor Injection and Setter Injection.

5.3.1.1. Constructor Injection

Constructor-based DI is effected by invoking a constructor with a number of arguments, each representing a dependency. Additionally, calling a static factory method with specific arguments to construct the object, can be considered almost equivalent, and the rest of this text will consider arguments to a constructor and arguments to a static factory method similarly. Find below an example of a class that could only be dependency injected using constructor injection. Notice that there is nothing special about this class.

public class SimpleMovieLister
{
  // the SimpleMovieLister has a dependency on a MovieFinder
  private IMovieFinder movieFinder;

  // a constructor so that the Spring container can 'inject' a MovieFinder
  public MovieLister(IMovieFinder movieFinder)
  {
    this.movieFinder = movieFinder;
  }

  // business logic that actually 'uses' the injected IMovieFinder is omitted...

}
5.3.1.1.1. Constructor Argument Resolution

Constructor argument resolution matching occurs using the argument's type. If there is no potential for ambiguity in the constructor arguments of a object definition, then the order in which the constructor arguments are defined in a object definition is the order in which those arguments will be supplied to the appropriate constructor when it is being instantiated. Consider the following class:

namespace X.Y
{
    public class Foo
    {
        public Foo(Bar bar, Baz baz)
        {
           // ...
        }
    }
}

There is no potential for ambiguity here (assuming of course that Bar and Baz classes are not related in an inheritance hierarchy). Thus the following configuration will work just fine, and you do not need to specify the constructor argument indexes and / or types explicitly.

<object name="Foo" type="X.Y.Foo, Example">
        <constructor-arg>
          <object type="X.Y.Bar, Example"/>
        </constructor-arg>
        <constructor-arg>
          <object type="X.Y.Baz, Example"/>
        </constructor-arg>
      </object>

When another object is referenced, the type is known, and matching can occur (as was the case with the preceding example). When a simple type is used, such as <value>true<value>, Spring cannot determine the type of the value, and so cannot match by type without help. Consider the following class:

using System;

namespace SimpleApp
{
  public class ExampleObject
  {
    private int years;              //No. of years to the calculate the Ultimate Answer

    private string ultimateAnswer;  //The Answer to Life, the Universe, and Everything

    public ExampleObject(int years, string ultimateAnswer)
    {
       this.years = years;
       this.ultimateAnswer = ultimateAnswer;
    }

}
5.3.1.1.1.1. Constructor Argument Type Matching

The above scenario can use type matching with simple types by explicitly specifying the type of the constructor argument using the type attribute. For example:

<object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
  <constructor-arg type="int" value="7500000"/>
  <constructor-arg type="string" value="42"/>
</object>

The type attribute specifies the System.Type of the constructor argument, such as System.Int32. Alias' are available to for common simple types (and their array equivalents). These alias' are...

Table 5.2. Type aliases

TypeAlias'Array Alias'
System.Charchar, Charchar[], Char()
System.Int16short, Shortshort[], Short()
System.Int32int, Integerint[], Integer()
System.Int64long, Longlong[], Long()
System.UInt16ushortushort[]
System.UInt32uintuint[]
System.UInt64ulongulong[]
System.Floatfloat, Singlefloat[], Single()
System.Doubledouble, Doubledouble[], Double()
System.Datedate, Datedate[], Date()
System.Decimaldecimal, Decimaldecimal[], Decimal()
System.Boolbool, Booleanbool[], Boolean()
System.Stringstring, Stringstring[], String()


5.3.1.1.1.2. Constructor Argument Index

Constructor arguments can have their index specified explicitly by use of the index attribute. For example:

<object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
  <constructor-arg index="0" value="7500000"/>
  <constructor-arg index="1" value="42"/>
</object>

As well as solving the ambiguity problem of multiple simple values, specifying an index also solves the problem of ambiguity where a constructor may have two arguments of the same type. Note that the index is 0 based.

5.3.1.1.1.3. Constructor Arguments by Name

Constructor arguments can also be specified by name by using the name attribute of the <constructor-arg> element.

<object name="exampleObject" type="SimpleApp.ExampleObject, SimpleApp">
  <constructor-arg name="years" value="7500000"/>
  <constructor-arg name="ultimateAnswer" value="42"/>
</object>

5.3.1.2. Setter Injection

Setter-based DI is realized by calling setter methods on your objects after invoking a no-argument constructor or no-argument static factory method to instantiate your object.

Find below an example of a class that can only be dependency injected using pure setter injection.

public class MovieLister
{
  private IMovieFinder movieFinder;

  public IMovieFinder MovieFinder
  {
      set
      {
          movieFinder = value;
      }
  }

  // business logic that actually 'uses' the injected IMovieFinder is omitted...
}

The IObjectFactory supports both of these variants for injecting dependencies into objects it manages. (It in fact also supports injecting setter-based dependencies after some dependencies have already been supplied via the constructor approach.) The configuration for the dependencies comes in the form of the IObjectDefinition class, which is used together with TypeConverters to know how to convert properties from one format to another. However, most users of Spring.NET will not be dealing with these classes directly (that is programatically), but rather with an XML definition file which will be converted internally into instances of these classes, and used to load an entire Spring IoC container instance.

Object dependency resolution generally happens as follows:

  1. The IObjectFactory is created and initialized with a configuration which describes all the objects. Most Spring.NET users use an IObjectFactory or IApplicationContext variant that supports XML format configuration files.

  2. Each object has dependencies expressed in the form of properties, constructor arguments, or arguments to the static-factory method when that is used instead of a normal constructor. These dependencies will be provided to the object, when the object is actually created.

  3. Each property or constructor argument is either an actual definition of the value to set, or a reference to another object in the container.

  4. Each property or constructor argument which is a value must be able to be converted from whatever format it was specified in, to the actual System.Type of that property or constructor argument. By default Spring.NET can convert a value supplied in string format to all built-in types, such as int, long, string, bool, etc. Spring.NET uses TypeConverter definitions to be able to convert string values to other, arbitrary types. Refer to Section 6.3, “Type conversion” for more information regarding type conversion, and how you can design your classes to be convertible by Spring.NET.

The Spring container validates the configuration of each object as the container is created, including the validation that properties which are object references are actually referring to valid object. However, the object properties themselves are not set until the object is actually created. For those object that defined as singletons and set to be pre-instantiated (such as singleton object in an IApplicationContext), creation happens at the time that the container is created, but otherwise this is only when the object is requested. When an object actually has to be created, this will potentially cause a graph of other objects to be created, as its dependencies and its dependencies' dependencies (and so on) are created and assigned.

You can generally trust Spring.NET to do the right thing. It will detect configuration issues, such as references to non-existent object definitions and circular dependencies, at container load-time. It will actually set properties and resolve dependencies as late as possible, which is when the object is actually created. This means that a Spring container which has loaded correctly can later generate an exception when you request an object if there is a problem creating that object or one of its dependencies. This could happen if the object throws an exception as a result of a missing or invalid property, for example. This potentially delayed visibility of some configuration issues is why IApplicationContext by default pre-instantiates singleton objects. At the cost of some upfront time and memory to create these objects before they are actually needed, you find out about configuration issues when the IApplicationContext is created, not later. If you wish, you can still override this default behavior and set any of these singleton objects to lazy-load (not be preinstantiated)

If no circular dependencies are involved (see sidebar for a discussion of circular dependencies), when one or more collaborating objects are being injected into a dependent object, each collaborating object is totally configured prior to being passed (via one of the DI flavors) to the dependent object. This means that if object A has a dependency on object B, the Spring IoC container will totally configure object B prior to invoking the setter method on object A; you can read 'totally configure' to mean that the object will be instantiated (if not a pre-instantiated singleton), all of its dependencies will be set, and the relevant lifecycle methods (such as a configured init method or the IIntializingObject callback method) will all be invoked.

5.3.1.3. Some examples

First, an example of using XML-based configuration metadata for setter-based DI. Find below a smallpart of a Spring XML configuration file specifying some object definitions.

<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">

    <!-- setter injection using the ref attribute -->
    <property name="objectOne" ref="anotherExampleObject"/>    
    <property name="objectTwo" ref="yetAnotherObject"/>
    <property name="IntegerProperty" value="1"/>
</object>

<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>

[C#]
public class ExampleObject
{
  private AnotherObject objectOne;
  private YetAnotherObject objectTwo;
  private int i;
  
  public AnotherObject ObjectOne
  {
    set { this.objectOne = value; }
  }
  
  public YetAnotherObject ObjectTwo
  {
    set { this.objectTwo = value; }
  }
  
  public int IntegerProperty
  {
    set { this.i = value; }
  }  
}

As you can see, setters have been declared to match against the properties specified in the XML file. Find below an example of using constructor-based DI.

<object id="exampleObject" type="Examples.ExampleObject, ExamplesLibrary">
    <constructor-arg name="objectOne" ref="anotherExampleObject"/>
    <constructor-arg name="objectTwo" ref="yetAnotherObject"/>
    <constructor-arg name="IntegerProperty" value="1"/>
</object>

<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>

[Visual Basic.NET]
Public Class ExampleObject

    Private myObjectOne As AnotherObject
    Private myObjectTwo As YetAnotherObject
    Private i As Integer
    
    Public Sub New (
        anotherObject as AnotherObject,
        yetAnotherObject as YetAnotherObject,
        i as Integer)
        
        myObjectOne = anotherObject
        myObjectTwo = yetAnotherObject
        Me.i = i
    End Sub
End Class

As you can see, the constructor arguments specified in the object definition will be used to pass in as arguments to the constructor of the ExampleObject.

Now consider a variant of this where instead of using a constructor, Spring is told to call a static factory method to return an instance of the object

<object id="exampleObject" type="Examples.ExampleFactoryMethodObject, ExamplesLibrary"
     factory-method="CreateInstance">
    <constructor-arg name="objectOne" ref="anotherExampleObject"/>
    <constructor-arg name="objectTwo" ref="yetAnotherObject"/>
    <constructor-arg name="intProp" value="1"/>
</object>

<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>

[C#]
public class ExampleFactoryMethodObject
{
  private AnotherObject objectOne;
  private YetAnotherObject objectTwo;
  private int i;
  
  // a private constructor
  private ExampleFactoryMethodObject()
  {
  }

  public static ExampleFactoryMethodObject CreateInstance(AnotherObject objectOne,
                               YetAnotherObject objectTwo,
                               int intProp)
  {
    ExampleFactoryMethodObject fmo = new ExampleFactoryMethodObject();
    fmo.AnotherObject = objectOne;
    fmo.YetAnotherObject = objectTwo;
    fmo.IntegerProperty = intProp;
    return fmo;
  }

  // Property definitions

}

Note that arguments to the static factory method are supplied via constructor-arg elements, exactly the same as if a constructor had actually been used. These arguments are optional. Also, it is important to realize that the type of the class being returned by the factory method does not have to be of the same type as the class which contains the static factory method, although in this example it is. An instance (non-static) factory method, mentioned previously, would be used in an essentially identical fashion (aside from the use of the factory-object attribute instead of the type attribute), so will not be detailed here.

Note that Setter Injection and Constructor Injectionare not mutually exclusive. It is perfectly reasonable to use both for a single object definition, as can be seen in the following example:

<object id="exampleObject" type="Examples.MixedIocObject, ExamplesLibrary">
    <constructor-arg name="objectOne" ref="anotherExampleObject"/>
    <property name="objectTwo" ref="yetAnotherObject"/>
    <property name="IntegerProperty" value="1"/>
</object>

<object id="anotherExampleObject" type="Examples.AnotherObject, ExamplesLibrary"/>
<object id="yetAnotherObject" type="Examples.YetAnotherObject, ExamplesLibrary"/>

[C#]
public class MixedIocObject
{
  private AnotherObject objectOne;
  private YetAnotherObject objectTwo;
  private int i;
  
  public MixedIocObject (AnotherObject obj)
  {
    this.objectOne = obj;
  }
  
  public YetAnotherObject ObjectTwo
  {
    set { this.objectTwo = value; }
  }
  
  public int IntegerProperty
  {
    set { this.i = value; }
  }  
}

5.3.2. Dependencies and configuration in detail

As mentioned in the previous section, object properties and constructor arguments can be defined as either references to other managed objects (collaborators), or values defined inline. Spring's XML-based configuration metadata supports a number of sub-element types within its <property/> and <constructor-arg/> elements for this purpose.a

5.3.2.1. Straight values (primitives, strings, etc.)

The <value/> element specifies a property or constructor argument as a human-readable string representation. As mentioned previously, TypeConverter instances are used to convert these string values from a System.String to the actual property or argument type. Custom TypeConverter implementations in the Spring.Objects.TypeConverters namespace are used to augment the functionality offered by the .NET BCL's default TypeConverter implementations.

In the following example, we use a SqlConnection from the System.Data.SqlClient namespace of the BCL. This class (like many other existing classes) can easily be used in a Spring.NET object factory, as it offers a convenient public property for configuration of its ConnectionString property.

objects xmlns="http://www.springframework.net">
  <object id="myConnection" type="System.Data.SqlClient.SqlConnection">
      <!-- results in a call to the setter of the ConnectionString property -->
      <property
          name="ConnectionString"
          value="Integrated Security=SSPI;database=northwind;server=mySQLServer"/>
  </object>
</objects>

5.3.2.1.1. The idref element

An idref element is simply a shorthand and error-proof way to set a property to the String id or name of another object in the container.

<object id="theTargetObject" type="..."> 
   . . .
</object>

<object id="theClientObject" type="...">
  <property name="targetName"> 
    <idref object="theTargetObject"/> 
  </property>
</object>

This is exactly equivalent at runtime to the following fragment:

<object id="theTargetObject" type="..."> 
  . . .
</object>

<object id="theClientObject" type="...">
  <property name="targetName" value="theTargetObject"/> 
</object>

The main reason the first form is preferable to the second is that using the idref tag will allow Spring.NET to validate at deployment time that the other object actually exists. In the second variation, the class that is having its targetName property injected is forced to do its own validation, and that will only happen when that class is actually instantiated by the container, possibly long after the container is actually up and running.

Additionally, if the object being referred to is in the same actual XML file, and the object name is the object id, the local attribute may be used, which will allow the XML parser itself to validate the object name even earlier, at parse time.

<property name="targetName">
  <idref local="theTargetObject"/> 
</property>

5.3.2.2. Referring to collaborating objects

The ref element is the final element allowed inside a property definition element. It is used to set the value of the specified property to be a reference to another object managed by the container, a collaborator, so to speak. As you saw in the previous example to set collection properties, we used the SqlConnection instance from the initial example as a collaborator and specified it using a <ref object/> element. As mentioned in a previous section, the referred-to object is considered to be a dependency of the object who's property is being set, and will be initialized on demand as needed (if it is a singleton object it may have already been initialized by the container) before the property is set. All references are ultimately just a reference to another object, but there are 3 variations on how the id/name of the other object may be specified, which determines how scoping and validation is handled.

Specifying the target object by using the object attribute of the ref tag is the most general form, and will allow creating a reference to any object in the same IObjectFactory / IApplicationContext (whether or not in the same XML file), or parent IObjectFactory / IApplicationContext. The value of the object attribute may be the same as either the id attribute of the target object, or one of the values in the name attribute of the target object.

<ref object="someObject"/>

Specifying the target object by using the local attribute leverages the ability of the XML parser to validate XML id references within the same file. The value of the local attribute must be the same as the id attribute of the target object. The XML parser will issue an error if no matching element is found in the same file. As such, using the local variant is the best choice (in order to know about errors are early as possible) if the target object is in the same XML file.

<ref local="someObject"/>

Specifying the target object by using the parent attribute allows a reference to be created to an object that is in a parent IObjectFactory (orIApplicationContext) of the current IObjectFactory (or IApplicationContext). The value of the parent attribute may be the same as either the id attribute of the target object, or one of the values in the name attribute of the target object, and the target object must be in a parent IObjectFactory or IApplicationContext of the current one. The main use of this object reference variant is when there is a need to wrap an existing object in a parent context with some sort of proxy (which may have the same name as the parent), and needs the original object so it may wrap it.

<ref parent="someObject"/>

5.3.2.3. Inline objects

An object element inside the property element is used to define an object value inline, instead of referring to an object defined elsewhere in the container. The inline object definition does not need to have any id or name defined (indeed, if any are defined, they will be ignored).

<object id="outer" type="...">

  <!-- Instead of using a reference to target, just use an inner object --> 

  <property name="target"> 
    <object type="ExampleApp.Person, ExampleApp"> 
      <property name="name" value="Tony"/> 
      <property name="age" value="51"/> 
    </object>
  </property>
</object>

5.3.2.4. Setting collection values

The list, set, name-values and dictionary elements allow properties and arguments of the type IList, ISet, NameValueCollection and IDictionary, respectively, to be defined and set.

<objects xmlns="http://www.springframework.net">
  <object id="moreComplexObject" type="Example.ComplexObject">
      <!--
      results in a call to the setter of the SomeList (System.Collections.IList) property
      -->
      <property name="SomeList">
          <list>
              <value>a list element followed by a reference</value>
              <ref object="myConnection"/>
          </list>
      </property>
      <!--
      results in a call to the setter of the SomeDictionary (System.Collections.IDictionary) property
      -->
      <property name="SomeDictionary">
          <dictionary>
              <entry key="a string => string entry" value="just some string"/>
              <entry key-ref="myKeyObject" value-ref="myConnection"/>
          </dictionary>
      </property>
      <!--
      results in a call to the setter of the SomeNameValue (System.Collections.NameValueCollection) property
      -->
      <property name="SomeNameValue">
          <name-values>
              <add key="HarryPotter" value="The magic property"/>
              <add key="JerrySeinfeld" value="The funny (to Americans) property"/>
          </name-values>
      </property>
      <!-- 
      results in a call to the setter of the SomeSet (Spring.Collections.ISet) property 
      -->
      <property name="someSet">
          <set>
              <value>just some string</value>
              <ref object="myConnection"/>
          </set>
      </property>
  </object>
</objects>

Many classes in the BCL expose only read-only properties for collection classes. When Spring.NET encounters a read-only collection, it will configure the collection by using the getter property to obtain a reference to the collection class and then proceed to add the additional elements to the existing collection. This results in an additive behavior for collection properties that are exposed in this manner.

Note that the value of a Dictionary entry, or a set value, can also again be any of the elements:

(object | ref | idref | expression | list | set | dictionary |
      name-values | value | null)

The shortcut forms for value and references are useful to reduce XML verbosity when setting collection properties. See Section 5.3.2.8, “Value and ref shortcut forms” for more information.

5.3.2.5. Setting generic collection values

Spring supports setting values for classes that expose properties based on the generic collection interfaces IList<T> and IDictionary<TKey, TValue>. The type parameter for these collections is specified by using the XML attribute element-type for IList<T> and the XML attributes key-type and value-type for IDictionary<TKey, TValue>. The values of the collection are automaticaly converted from a string to the appropriate type. If you are using your own user-defined type as a generic type parameter you will likely need to register a custom type converter. Refer to Section 5.5, “Type conversion” for more information. The implementations of IList<T> and IDictionary<TKey, TValue> that is created are System.Collections.Generic.List and System.Collections.Generic.Dictionary.

The following class represents a lottery ticket and demonstrates how to set the values of a generic IList.

public class LotteryTicket { 

  List<int> list;

  DateTime date; 

  public List<int> Numbers { 
    set { list = value; }
    get { return list; } 
  }

  public DateTime Date { 
    get { return date; } 
    set { date = value; } 
  } 
}

The XML fragment that can be used to configure this class is shown below

<object id="MyLotteryTicket" type="GenericsPlay.Lottery.LotteryTicket, GenericsPlay">
  <property name="Numbers"> 
    <list element-type="int"> 
      <value>11</value>
      <value>21</value> 
      <value>23</value>
      <value>34</value> 
      <value>36</value>
      <value>38</value> 
    </list> 
  </property>
  <property name="Date" value="4/16/2006"/>
</object>

The following shows the definition of a more complex class that demonstrates the use of generics using the Spring.Expressions.IExpression interface as the generic type parameter for the IList element-type and the value-type for IDictionary. Spring.Expressions.IExpression has an associated type converter, Spring.Objects.TypeConverters.ExpressionConverter that is already pre-registered with Spring.

    public class GenericExpressionHolder
    {
        private System.Collections.Generic.IList<IExpression> expressionsList;

        private System.Collections.Generic.IDictionary<string,IExpression> expressionsDictionary;

        public System.Collections.Generic.IList<IExpression> ExpressionsList
        {
            set { this.expressionsList = value; }
        }

        public System.Collections.Generic.IDictionary<string, IExpression> ExpressionsDictionary
        {
            set { this.expressionsDictionary = value; }
        }

        public IExpression this[int index]
        {
            get
            {
                return this.expressionsList[index];
            }
        }

        public IExpression this[string key]
        {
            get { return this.expressionsDictionary[key]; }
        }
    }

An example XML configuration of this class is shown below

<object id="genericExpressionHolder"
    type="Spring.Objects.Factory.Xml.GenericExpressionHolder,
    Spring.Core.Tests">
    <property name="ExpressionsList">
        <list element-type="Spring.Expressions.IExpression, Spring.Core">
            <value>1 + 1</value>
            <value>date('1856-7-9').Month</value>
            <value>'Nikola Tesla'.ToUpper()</value>
            <value>DateTime.Today > date('1856-7-9')</value>
        </list>
    </property>
    <property name="ExpressionsDictionary">
        <dictionary key-type="string" value-type="Spring.Expressions.IExpression, Spring.Core">
            <entry key="zero">
                <value>1 + 1</value>
            </entry>
            <entry key="one">
                <value>date('1856-7-9').Month</value>
            </entry>
            <entry key="two">
                <value>'Nikola Tesla'.ToUpper()</value>
            </entry>
            <entry key="three">
                <value>DateTime.Today > date('1856-7-9')</value>
            </entry>
        </dictionary>
    </property>
</object>

5.3.2.6. Setting null values

The <null> element is used to handle null values. Spring.NET treats empty arguments for properties and constructor arguments as empty string instances. The following configuration demonstrates this behaviour...

<object type="Examples.ExampleObject, ExamplesLibrary"> 
  <property name="email"><value></value></property>

  <!-- equivalent, using value attribute as opposed to nested <value/> element... 
  <property name="email" value=""/> 
</object>

This results in the email property being set to the empty string value (""), in much the same way as can be seen in the following snippet of C# code...

exampleObject.Email = "";

The special <null/> element may be used to indicate a null value; to wit...

<object type="Examples.ExampleObject, ExamplesLibrary"> 
  <property name="email"><null/></property>
</object>

This results in the email property being set to null, again in much the same way as can be seen in the following snippet of C# code...

exampleObject.Email = null;

5.3.2.7. Setting indexer properties

An indexer lets you set and get values from a collection using a familiar bracket [] notation. Spring's XML configuration supports the setting of indexer properties. Overloaded indexers as well as multiparameter indexers are also supported. The property expression parser described in Chapter 11, Expression Evaluation is used to perform the type conversion of the indexer name argument from a string in the XML file to a matching target type. As an example consider the following class

public class Person
{
    private IList favoriteNames = new ArrayList();

    private IDictionary properties = new Hashtable();

    public Person()
    {
        favoriteNames.Add("p1");
        favoriteNames.Add("p2");
    }

    public string this[int index]
    {
        get { return (string) favoriteNames[index]; }
        set { favoriteNames[index] = value; }
    }

    public string this[string keyName]
    {
        get { return (string) properties[keyName]; }
        set { properties.Add(keyName, value); }
    }
}

The XML configuration snippet to populate this object with data is shown below

<object id="person" type="Test.Objects.Person, Test.Objects">
    <property name="[0]" value="Master Shake"/>
    <property name="['one']" value="uno"/>
</object>
[Note]Note
The use of the property expression parser in Release 1.0.2 changed how you configure indexer properties. The following section describes this usage.

The older style configuration uses the following syntax

<object id="objectWithIndexer" type="Spring.Objects.TestObject, Spring.Core.Tests">
    <property name="Item[0]" value="my string value"/>
</object>

You can also change the name used to identify the indexer by adorning your indexer method declaration with the attribute [IndexerName("MyItemName")]. You would then use the string MyItemName[0] to configure the first element of that indexer.

There are some limitations to be aware in the older indexer configuration. The indexer can only be of a single parameter that is convertible from a string to the indexer parameter type. Also, multiple indexers are not supported. You can get around that last limitation currently if you use the IndexerName attribute.

5.3.2.8. Value and ref shortcut forms

There are also some shortcut forms that are less verbose than using the full value and ref elements. The property, constructor-arg, and entry elements all support a value attribute which may be used instead of embedding a full value element. Therefore, the following:

<property name="myProperty">
      <value>hello</value>
</property>

<constructor-arg> 
  <value>hello</value>
</constructor-arg> 

<entry key="myKey">
  <value>hello</value>
</entry>

are equivalent to:

<property name="myProperty" value="hello"/>

<constructor-arg value="hello"/> 

<entry key="myKey" value="hello"/>

In general, when typing definitions by hand, you will probably prefer to use the less verbose shortcut form.

The property and constructor-arg elements support a similar shortcut ref attribute which may be used instead of a full nested ref element. Therefore, the following...

<property name="myProperty"> 
  <ref object="anotherObject"/>
</property>

<constructor-arg index="0"> 
  <ref object="anotherObject"/> 
</constructor-arg>

is equivalent to...

<property name="myProperty" ref="anotherObject"/>

<constructor-arg index="0" ref="anotherObject"/>
[Note]Note
The shortcut form is equivalent to a <ref object="xxx"> element; there is no shortcut for either the <ref local="xxx"> or <ref parent="xxx"> elements. For a local or parent ref, you must still use the long form.

Finally, the entry element allows a shortcut form the specify the key and/or value of a dictionary, in the form of key/key-ref and value/value-ref attributes. Therefore, the following

<entry> 
  <key>
     <ref object="MyKeyObject"/>
  </key> 
  <ref object="MyValueObject"/> 
</entry>

Is equivalent to:

<entry key-ref="MyKeyObject" value-ref="MyValueObject"/>

As mentioned previously, the equivalence is to <ref object="xxx"> and not the local or parent forms of object references.

5.3.2.9. Compound property names and Spring expression references

Note that compound or nested property names are perfectly legal when setting object properties. Property names are interpreted using the Spring Expression Language (SpEL) and therefore can leverage its many features to set property names. For example, in this object definition a simple nested property name is configured

<object id="foo" type="Spring.Foo, Spring.Foo"> 
  <property name="bar.baz.name" value="Bingo"/> 
</object>

As an example of some alternative ways to declare the property name, you can use SpEL's support for indexers to configure a Dictionary key value pair as an alternative to the nested <dictionary> element. More importantly, you can use the 'expression' element to refer to a Spring expression as the value of the property. Simple examples of this are shown below

<property name=“minValue” expression=“int.MinValue” />

<property name=“weekFromToday” expression="DateTime.Today + 7"/>

Using SpEL's support for method evaluation, you can easily call static method on various helper classes in your XML configuraiton.

5.3.3. Using depends-on

For most situations, the fact that an object is a dependency of another is expressed by the fact that one object is set as a property of another. This is typically accomploished with the <ref/> element in XML-based configuration metadata. For the relatively infrequent situations where dependencies between objects are less direct (for example, when a static initializer in a class needs to be triggered) the 'depends-on' attribute may be used to explicitly force one or more objects to be initialized before the object using this element is initialized. Find below an example of using the 'depends-on' attribute to express a dependency on a single object..

<object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager">
  <property name="manager" ref="manager"/>
</object>

<object id="manager" type="Examples.ManagerObject, ExamplesLibrary"/>

If you need to express a dependency on multiple objects, you can supply a list of object names as the value of the 'depends-on' attribute, with commas, whitespace and semicolons all valid delimiters, like so:

<object id="objectOne" type="Examples.ExampleObject, ExamplesLibrary" depends-on="manager,accountDao">
  <property name="manager" ref="manager" />
</object>

<object id="manager" type="Examples.ManagerObject, ExamplesLibrary" />
<object id="accountDao" type="Examples.AdoAccountDao, ExamplesLibrary" />
[Note]Note

The 'depends-on' attribute and property is used not only to specify an initialization time dependency, but also to specify the corresponding destroy time dependency (in the case of singleton objects only). Dependent objects that are defined in the 'depends-on' attribute will be destroyed after the relevant object itself is destroyed. This thus allows you to control shutdown order too

5.3.4. Lazily-instantiated objects

The default behavior for IApplicationContext implementations is to eagerly pre-instantiate all singleton objects at startup. Pre-instantiation means that an IApplicationContext will eagerly create and configure all of its singleton objects as part of its initialization process. Generally this is a good thing, because it means that any errors in the configuration or in the surrounding environment will be discovered immediately (as opposed to possibly hours or even days down the line).

However, there are times when this behavior is not what is wanted. If you do not want a singleton object to be pre-instantiated when using an IApplicationContext, you can selectively control this by marking an object definition as lazy-initialized. A lazily-initialized object indicates to the IoC container whether or not an object instance should be created at startup or when it is first requested.

When configuring objects via XML, this lazy loading is controlled by the 'lazy-init'attribute on the <object/> element; for example:

<object id="lazy" type="MyCompany.ExpensiveToCreateObject, MyApp" lazy-init="true"/>

<object name="not.lazy" type="MyCompany.AnotherObject, MyApp"/>

When the above configuration is consumed by an IApplicationContext, the object named 'lazy' will not be eagerly pre-instantiated when the IApplicationContext is starting up, whereas the 'not.lazy' object will be eagerly pre-instantiated.

One thing to understand about lazy-initialization is that even though an object definition may be marked up as being lazy-initialized, if the lazy-initialized object is the dependency of a singleton object that is not lazy-initialized, when the IApplicationContext is eagerly pre-instantiating the singleton, it will have to satisfy all of the singletons dependencies, one of which will be the lazy-initialized object! So don't be confused if the IoC container creates one of the objects that you have explicitly configured as lazy-initialized at startup; all that means is that the lazy-initialized object is being injected into a non-lazy-initialized singleton object elsewhere.

It is also possible to control lazy-initialization at the container level by using the 'default-lazy-init'attribute on the <objects/> element; for example:

<objects default-lazy-init="true">
  <!-- no objects will be pre-instantiated... -->
</objects>

5.3.5. Autowiring collaborators

The Spring container is able to autowire relationships between collaborating objects. This means that it is possible to automatically let Spring resolve collaborators (other objects) for your object by inspecting the contents of the IoC container.. The autowiring functionality has five modes. Autowiring is specified per object and can thus be enabled for some object, while other objects will not be autowired. Using autowiring, it is possible to reduce or eliminate the need to specify properties or constructor arguments, thus saving a significant amount of typing. When using XML-based configuration metadata, the autowire mode for an object definition is specified by using the autowire attribute of the <object/> element. The following values are allowed:

Table 5.3. Autowiring modes

ModeExplanation
noNo autowiring at all. This is the default value and you are encouraged not to change this for large applications, since specifying your collaborators explicitly gives you a feeling for what you're actually doing (always a bonus) and is a great way of somewhat documenting the structure of your system.
byNameThis option will inspect the objects within the container, and look for an object named exactly the same as the property which needs to be autowired. For example, if you have an object definition that is set to autowire by name, and it contains a Master property, Spring.NET will look for an object definition named Master, and use it as the value of the Master property on your object definition.
byTypeThis option gives you the ability to resolve collaborators by type instead of by name. Supposing you have an IObjectDefinition with a collaborator typed SqlConnection, Spring.NET will search the entire object factory for an object definition of type SqlConnection and use it as the collaborator. If 0 (zero) or more than 1 (one) object definitions of the desired type exist in the container, a failure will be reported and you won't be able to use autowiring for that specific object.
constructorThis is analogous to byType, but applies to constructor arguments. If there isn't exactly one object of the constructor argument type in the object factory, a fatal error is raised.
autodetectChooses constructor or byType through introspection of the object class. If a default constructor is found, byType gets applied.


Note that explicit dependencies in property and constructor-arg settings always override autowiring. Please also note that it is not currently possible to autowire so-called simple properties such as primitives, Strings, and Types (and arrays of such simple properties). (This is by-design and should be considered a feature.) When using either the byType or constructor autowiring mode, it is possible to wire arrays and typed-collections. In such cases all autowire candidates within the container that match the expected type will be provided to satisfy the dependency. Strongly-typed IDictionaries can even be autowired if the expected key type is string. An autowired IDictionary values will consist of all object instances that match the expected type, and the IDictionary's keys will contain the corresponding object names.

Autowire behavior can be combined with dependency checking, which will be performed after all autowiring has been completed. It is important to understand the various advantages and disadvantages of autowiring. Some advantages of autowiring include:

  • Autowiring can significantly reduce the volume of configuration required. However, mechanisms such as the use of a object template (discussed elsewhere in this chapter) are also valuable in this regard.

  • Autowiring can cause configuration to keep itself up to date as your objects evolve. For example, if you need to add an additional dependency to a class, that dependency can be satisfied automatically without the need to modify configuration. Thus there may be a strong case for autowiring during development, without ruling out the option of switching to explicit wiring when the code base becomes more stable.

Some disadvantages of autowiring:

  • Autowiring is more magical than explicit wiring. Although, as noted in the above table, Spring is careful to avoid guessing in case of ambiguity which might have unexpected results, the relationships between your Spring-managed objects are no longer documented explicitly.

  • Wiring information may not be available to tools that may generate documentation from a Spring container.

Another issue to consider when autowiring by type is that multiple object definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or IDictionary, this is not necessarily a problem. However for dependencies that expect a single value, this ambiguity will not be arbitrarily resolved. Instead, if no unique object definition is available, an Exception will be thrown.

When deciding whether to use autowiring, there is no wrong or right answer in all cases. A degree of consistency across a project is best though; for example, if autowiring is not used in general, it might be confusing to developers to use it just to wire one or two object definitions.

5.3.6. Checking for dependencies

Spring.NET has the ability to try to check for the existence of unresolved dependencies of an object deployed into the container. These are properties of the object, which do not have actual values set for them in the object definition, or alternately provided automatically by the autowiring feature.

This feature is sometimes useful when you want to ensure that all properties (or all properties of a certain type) are set on an object. Of course, in many cases an object class will have default values for many properties, or some properties do not apply to all usage scenarios, so this feature is of limited use. Dependency checking can also be enabled and disabled per object, just as with the autowiring functionality. The default dependency checking mode is to not check dependencies. Dependency checking can be handled in several different modes. In XML-based configuration, this is specified via the dependency-check attribute in an object definition, which may have the following values.

Table 5.4. Dependency checking modes

ModeExplanation
noneNo dependency checking. Properties of the object which have no value specified for them are simply not set.
simpleDependency checking is done for primitive types and collections (this means everything except collaborators).
objectDependency checking is done for collaborators only.
allDependency checking is done for collaborators, primitive types and collections.


5.3.7. Method Injection

For most users, the majority of the objects in the container will be singletons. When a singleton object needs to collaborate with (use) another singleton object, or a non-singleton object needs to collaborate with another non-singleton object, the typical and common approach of handling this dependency (by defining one object to be a property of the other) is quite adequate. There is however a problem when the object lifecycles are different. Consider a singleton object A which needs to use a non-singleton (prototype) object B, perhaps on each method invocation on A. The container will only create the singleton object A once, and thus only get the opportunity to set its properties once. There is no opportunity for the container to provide object A with a new instance of object B every time one is needed.

One solution to this problem is to forego some inversion of control. Object A can be made aware of the container by implementing the IObjectFactoryAware interface, and use programmatic means to ask the container via a GetObject("B") call for (a typically new) object B every time it needs it. Find below an admittedly somewhat contrived example of this approach

using System.Collections;
using Spring.Objects.Factory;

namespace Fiona.Apple
{
    public class CommandManager : IObjectFactoryAware
    {
        private IObjectFactory objectFactory;

        public object Process(IDictionary commandState)
        {
            // grab a new instance of the appropriate Command
            Command command = CreateCommand();
            // set the state on the (hopefully brand new) Command instance
            command.State = commandState;
            return command.Execute();
        }

        // the Command returned here could be an implementation that executes asynchronously, or whatever
        protected Command CreateCommand()
        {
            return (Command) objectFactory.GetObject("command");  // notice the Spring API dependency 
        }

        public IObjectFactory ObjectFactory
        {
            set { objectFactory = value; }
        }
    }
}

The above example is generally not a desirable solution since the business code is then aware of and coupled to the Spring Framework. Method Injection, a somewhat advanced feature of the Spring IoC container, allows this use case to be handled in a clean fashion.

5.3.7.1. Lookup Method Injection

Lookup method injection refers to the ability of the container to override abstract or concrete methods on container managed objects, to return the result of looking up another named object in the container. The lookup will typically be of a prototype object as in the scenario described above. The Spring framework implements this method injection by a dynamically generating a subclass overriding the method using the classes in the System.Reflection.Emit namespace. You can read more about the motivation for Method Injection in this blog entry.

So if you look at the code from the previous code snipped (the CommandManager class), the Spring container is going to dynamically override the implementation of the CreateCommand() method. Your CommandManager class is not going to have any Spring dependencies, as can be seen in this reworked example below:

using System.Collections;

namespace Fiona.Apple
{
    public abstract class CommandManager
    {

        public object Process(IDictionary commandState)
        {
            Command command = CreateCommand();
            command.State = commandState;
            return command.Execute();
        }

        // okay... but where is the implementation of this method?
        protected abstract Command CreateCommand();
    }
}

In the client class containing the method to be injected (the CommandManager in this case) the method definition must observe the following form:

<public|protected> [abstract] <return-type> TheMethodName(no-arguments);

If the method is abstract, the dynamically-generated subclass will implement the method. Otherwise, the dynamically-generated subclass will override the concrete method defined in the original class. Let's look at an example:

<!-- a stateful object deployed as a prototype (non-singleton) -->
<object id="command" class="Fiona.Apple.AsyncCommand, Fiona" singleton="false">
  <!-- inject dependencies here as required -->
</object>

<!-- commandProcessor uses a statefulCommandHelpder -->
<object id="commandManager" type="Fiona.Apple.CommandManager, Fiona">
  <lookup-method name="CreateCommand" object="command"/>
</object>

The object identified as commandManager will call its own method CreateCommand whenever it needs a new instance of the command object. It is important to note that the person deploying the objects must be careful to deploy the command object as prototype (if that is actually what is needed). If it is deployed as a singleton the same instance of singleShotHelper will be returned each time!

Note that lookup method injection can be combined with Constructor Injection (supplying optional constructor arguments to the object being constructed), and also with Setter Injection (settings properties on the object being constructed).

5.3.7.2. Arbitrary method replacement

A less commonly useful form of method injection than Lookup Method Injection is the ability to replace arbitrary methods in a managed object with another method implementation. Users may safely skip the rest of this section (which describes this somewhat advanced feature), until this functionality is actually needed.

In an XmlObjectFactory, the replaced-method element may be used to replace an existing method implementation with another. Consider the following class, with a method ComputeValue, which we want to override:

public class MyValueCalculator {

  public virtual string ComputeValue(string input) {
    // ... some real code
  }

  // ... some other methods
}

A class implementing the Spring.Objects.Factory.Support.IMethodReplacer interface is needed to provide the new (injected) method definition.

/// <summary>
/// Meant to be used to override the existing ComputeValue(string)
/// implementation in MyValueCalculator.
/// </summary>
public class ReplacementComputeValue : IMethodReplacer 
{
	public object Implement(object target, MethodInfo method, object[] arguments)
	{
		// get the input value, work with it, and return a computed result...
		string value = (string) arguments[0];
		// compute...
		return result;
	}
}

The object definition to deploy the original class and specify the method override would look like this:

<object id="myValueCalculator" type="Examples.MyValueCalculator, ExampleAssembly">
  <!-- arbitrary method replacement -->
  <replaced-method name="ComputeValue" replacer="replacementComputeValue">
    <arg-type match="String"/>
  </replaced-method>
</object>

<object id="replacementComputeValue" type="Examples.ReplacementComputeValue, ExampleAssembly"/>

One or more contained arg-type elements within the replaced-method element may be used to indicate the method signature of the method being overridden. Note that the signature for the arguments is actually only needed in the case that the method is actually overloaded and there are multiple variants within the class. For convenience, the type string for an argument may be a substring of the fully qualified type name. For example, all the following would match System.String.

    System.String
    String
    Str

Since the number of arguments is often enough to distinguish between each possible choice, this shortcut can save a lot of typing, by just using the shortest string which will match an argument.

5.3.8. Setting a reference using the members of other objects and classes.

This section details those configuration scenarios that involve the setting of properties and constructor arguments using the members of other objects and classes. This kind of scenario is quite common, especially when dealing with legacy classes that you cannot (or won't) change to accommodate some of Spring.NET's conventions... consider the case of a class that has a constructor argument that can only be calculated by going to say, a database. The MethodInvokingFactoryObject handles exactly this scenario ... it will allow you to inject the result of an arbitrary method invocation into a constructor (as an argument) or as the value of a property setter. Similarly, PropertyRetrievingFactoryObject and FieldRetrievingFactoryObject allow you to retrieve values from another object's property or field value. These classes implement the IFactoryObject interface which indicates to Spring.NET that this object is itself a factory and the factories product, not the factory itself, is what will be associated with the object id. Factory objects are discussed further in ???

5.3.8.1. Setting a reference to the value of property.

The PropertyRetrievingFactoryObject is an IFactoryObject that addresses the scenario of setting one of the properties and / or constructor arguments of an