Using the Simple Injector

This section will walk you through the basics of the Simple Injector. After reading this section, you will have a good idea how to configure and use the Simple Injector.

Resolving instances

A good practice is to minimize the dependency between your application and the IoC framework. This increases the testability and the flexibility of the application, results in cleaner code, and makes it easier to migrate to another IoC framework when required. Minimizing can be achieved by designing the types in your application around the constructor injection pattern. Define all dependencies of a class in the single public constructor of that type. Do this for all service types that need to be resolved and resolve only the top most types in the application directly (let the container build up the complete graph of dependent objects for you).

The Simple Injector allows two scenarios by which you can retrieve instances:
1. Getting an object by a specified type
var repository = container.GetInstance<IUserRepository>();

// Alternatively, you can use the weakly typed version
var repository = (IUserRepository)container.GetInstance(typeof(IUserRepository));
2. Getting a collection of objects by their type
IEnumerable<ICommand> commands = container.GetAllInstances<ICommand>();

// Alternatively, you can use the weakly typed version
IEnumerable<object> commands = container.GetAllInstances(typeof(ICommand));

Using the Simple Injector

The Simple Injector's main type is the Container class. An instance of Container is used to register mappings between an abstraction (service) and implementation (component). Your application depends on abstractions, and it is the role of the Container to supply the application with the right implementation. The easiest way to look at a Container is as a big dictionary where the type of the abstraction is used as key, and its value is the definition of how to create the implementation. When the application requests for a service, it is looked up in the dictionary, and the correct implementation is returned.

You should typically create a single Container instance for the whole application (app domain); Container instances are thread-safe.

Creating a new container is done by newing up a new instance and start calling the RegisterXXX overloads to register new services:

Container container = new SimpleInjector.Container();

// Registrations here
container.Register<ILogger, FileLogger>();

Ideally, the only place in an application that should directly reference and use the Simple Injector is the startup path. For an ASP.NET Web Forms or MVC application this will usually be the Application_OnStart event in the Global.asax page of the web application project. For a Windows Forms or console application this will be the Main method in the application assembly.
For more information about usage of the Simple Injector for a specific technology, please see the Integration Guide.
The usage of the Simple Injector consists of four or five simple steps:
  1. Create a new container
  2. Configure the container (register)
  3. Optionally verify the container
  4. Store the container for use by the application
  5. Retrieve instances from the container (resolve)
While the first three steps are platform agnostic, performing the last two steps depends on your own taste and which presentation framework you use, but below is an example for an ASP.NET Web Forms application:

using SimpleInjector;

public class Global : System.Web.HttpApplication 
{
    public static Container Container { get; private set; }

    protected void Application_Start(object sender, EventArgs e) 
    {
        // 1. Create a new Simple Injector container
        var container = new Container();

        // 2. Configure the container (register)
        container.Register<IUserService, UserService>();
        container.RegisterSingle<IUserRepository, SqlUserRepository>();

        // See below for more configuration examples

        // 3. Optionally verify the container's configuration.
        container.Verify();

        // 4. Store the container for use by Page classes.
        Global.Container = container;
    }
}
The example below shows the fifth step inside a ASP.NET Web Page:

using System;

public partial class User : BasePage
{
    private readonly IUserRepository repository;
    private readonly ILogger logger;

    public User()
    {
        // 5. Retrieve instances from the container (resolve)
        this.repository = Global.Container.GetInstance<IUserRepository>();
        this.logger = Global.Container.GetInstance<ILogger>();
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        // Use repository and logger here.
    }
}
Note: Calling the GetInstance method in the constructor is suboptimal and should be avoided whenever possible. With ASP.NET Web Forms however, it is hard to completely avoid this. Please see the Integration Guide for alternatives.

Configuring the Simple Injector

The Container class consists of several methods that enable registering instances to be retrieved when requested from the application. These methods enable most common scenario's. Here are the most common scenario's with a code example per scenario:

Configuring an automatically constructed single instance to be always returned:
The following example configures that a single instance of type RealUserService will always be returned when an instance of IUserService is requested. The RealUserService will be constructed using automatic constructor injection.
// Configuration
container.RegisterSingle<IUserService, RealUserService>();

// Usage
IUserService service = container.GetInstance<IUserService>();
Note: instances that are declared as Single should be thread-safe in a multi-threaded environment.
Configuring a single -manually created- instance to be always returned:
The following example configures a single instance that will always be returned when an instance of that type will be requested.
// Configuration
container.RegisterSingle<IUserRepository>(new SqlUserRepository());

// Usage
IUserRepository repository = container.GetInstance<IUserRepository>();
Note: Registering types using automatic constructor injection (auto-wiring) is the preferred way of registering types. Only new up instances manually when automatic constructor injection is not possible.
Configuring a single instance using a delegate:
The following example configures a single instance using a delegate. The container will ensure that the delegate is not called more than once.
// Configuration
container.RegisterSingle<IUserRepository>(() => UserRepFactory.Create("some constr"));

// Usage
IUserRepository repository = container.GetInstance<IUserRepository>();
Note: Registering types using automatic constructor injection (auto-wiring) is the preferred way of registering types. Only new up instances manually when automatic constructor injection is not possible.
Configuring an automatically constructed new instance to be returned:
By supplying the service type and the created implementation as generic types, the container can create new instances of the implementation (MoveCustomerHandler in this case) by using automatic constructor injection.
// Configuration
container.Register<IHandler<MoveCustomerCommand>, MoveCustomerHandler>();

// Usage
var handler = container.GetInstance<IHandler<MoveCustomerCommand>>();

Configuring a new instance to be returned on each call using a delegate:
By supplying a delegate, types can be registered that can not be created by using automatic constructor injection. By calling the container inside the delegate, you can let the container do as much as work for you as possible:
// Configuration
container.Register<IHandler<MoveCustomerCommand>>(() =>
{
    // Get a new instance of the concrete MoveCustomerHandler class:
    var handler = container.GetInstance<MoveCustomerHandler>();

    // Configure the handler:
    handler.ExecuteAsynchronously = true;

    return handler;
});

// Usage
var handler = container.GetInstance<IHandler<MoveCustomerCommand>>();

Configuring property injection on an instance:
For types that need to be injected, define a single public constructor that holds all dependencies whenever possible. In scenarios where constructor injection is not possible, property injection is your second best pick. The previous example already showed an example of this. The preferred way of doing this however, is by using the RegisterInitializer method:
// Configuration
container.Register<IHandler<MoveCustomerCommand>>, MoveCustomerHandler>();
container.Register<IHandler<ShipOrderCommand>>, ShipOrderHandler>();

// MoveCustomerCommand and ShipOrderCommand both inherit from HandlerBase
container.RegisterInitializer<HandlerBase>(handlerToInitialize =>
{
    handlerToInitialize.ExecuteAsynchronously = true;
});

// Usage
var handler1 = container.GetInstance<IHandler<MoveCustomerCommand>>();
Assert.IsTrue(handler1.ExecuteAsynchronously);

var handler2 = container.GetInstance<IHandler<ShipOrderCommand>>();
Assert.IsTrue(handler2.ExecuteAsynchronously);
The Action<T> delegate that is registered using the RegisterInitializer method will be called after the container created a new instance that inherits from or implements the given T (or inherits from or implements the given T). In the case of the given example, the MoveCustomerHandler inherits from HandlerBase and because of this, Action<HandlerBase> delegate will get called with the reference to the created instance.
Note: The container will not be able to call an initializer delegate on a type that is manually constructed using the new operator. Use automatic constructor injection whenever possible.
Tip: Multiple initializers can apply to a concrete type and the container will call all initializers that apply to that type. They are guaranteed to run in the same order as they are registered.
Configuring a collection of instances to be returned:
The Simple Injector contains several methods for registration and resolving collections of types. Here are some examples:
// Configuration
// Register a fixed list (these instances should be thread-safe).
container.RegisterAll<ILogger>(new MailLogger(), new SqlLogger());

// Using a collection from another subsystem
container.RegisterAll<ILogger>(Logger.Providers);

// A list that consists of items in the container
IEnumerable<ILogger> loggers = AllLoggers(container);
container.RegisterAll<ILogger>(loggers);

static IEnumerable<ILogger> AllLoggers(Container container)
{
    yield return container.GetInstance<MailLogger>();
    yield return container.GetInstance<SqlLogger>();
}

// Usage
var loggers = container.GetAllInstances<ILogger>();
Note: When no instances are registered using RegisterAll, Container.GetAllInstances will always return an empty list.
Tip: The SimpleInjector.Extensions.dll contains several extension methods that allow registering collection by lists of System.Type objects.
Just as with normal types, the Simple Injector can inject collections of instances into constructors:
// Definition
public class Service : IService
{
    private readonly IEnumerable<ILogger> loggers;

    public Service(IEnumerable<ILogger> loggers)
    {
        this.loggers = loggers;
    }

    void IService.DoStuff()
    {
        // Log to all loggers
        foreach (var logger in this.loggers)
        {
            logger.Log("Some message");
        }
    }
}

// Configuration
container.RegisterAll<ILogger>(new MailLogger(), new SqlLogger());
container.RegisterSingle<IService, Service>();

// Usage
var service = container.GetInstance<IService>();
service.DoStuff();
While resolving collections is useful and also works with automatic constructor injection, the registration of composites is preferred over the registration collections. Register a composite whenever possible, as shown in the example below:
// Definition
public class CompositeLogger : ILogger
{
    private readonly ILogger[] loggers;

    public CompositeLogger(params ILogger[] loggers)
    {
        this.loggers = loggers;
    }

    public void Log(string message)
    {
        foreach (var logger in this.loggers)
            logger.Log(message);
    }
}

// Configuration
container.RegisterSingle<IService, Service>();
container.RegisterSingle<ILogger>(() => 
    new CompositeLogger(
        container.GetInstance<MailLogger>(),
        container.GetInstance<SqlLogger>()
    )
);

// Usage
var service = container.GetInstance<IService>();
service.DoStuff();
When using the approach given above, your services don’t need a dependency on IEnumerable<ILogger>, but can simply have a dependency on the ILogger interface itself.

Verifying the container's configuration

Optionally, you can call the Verify method of the Container. This method allows a fail-fast mechanism to prevent the application to start when the container is misconfigured. The Verify method checks the container's configuration by creating an instance of all registered types.

For more information about creating an application and container configuration that can be succesfully verified, please read the How To Verify the container’s configuration.

Automatic constructor injection / auto-wiring.

The Simple Injector uses the public constructor of a registered type and looks at the arguments of that constructor. The container will resolve instances for the argument types and invokes the constructor using those instances. This mechanism is called automatic constructor injection or auto-wiring and this is one of the core differences that separates DI containers from doing injection manually. For the Simple Injector to be able to use auto-wiring, the following requirements must be met:
  1. The type is concrete (not abstract, no interface, no generic type definition).
  2. The type has exactly one public constructor (this may be a default constructor).
  3. All types of the arguments on that constructor can be resolved by the container.
The Simple Injector can create a type even if it hasn’t registered in the container by using constructor injection.

The following code shows an example of the use of automatic constructor injection. The example shows an IUserRepository interface with a concrete SqlUserRepository implementation and a concrete UserService class. The UserService class has one public constructor with an IUserRepository argument. Because the dependencies of the UserService are registered, the Simple Injector is able to create a new UserService instance.
// Definitions
public interface IUserRepository { }
public class SqlUserRepository : IUserRepository { }
public class UserService : IUserService
{
    public UserService(IUserRepository repository) { }
}

// Configuration
var container = new Container();

container.RegisterSingle<IUserRepository, SqlUserRepository>();
container.RegisterSingle<IUserService, UserService>();

// Usage
var service = container.GetInstance<IUserService>();
Note: Because UserService is a concrete type, calling container.GetInstance<UserService>() without registering it explicitly will work as well. This can simplify the container’s configuration significantly for more complex scenarios. However, keep in mind that the best practice is to program to an interface, not a concrete type. Prevent using and depending on concrete types whenever possible.

More information

For more information about the Simple Injector please visit the following links:

Last edited Jul 5, 2012 at 10:24 AM by dot_NET_Junkie, version 16

Comments

No comments yet.