Note: this documentation is specific for Simple Injector version 2.0 and up. Look here for 1.x specific documentation.

Using Simple Injector

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

Using Simple Injector

A good practice is to minimize the dependency between your application and the IoC framework. This increases the testability and the flexibility of your application, results in cleaner code, and makes it easier to migrate to another IoC framework if ever 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).

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 code should depend 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.

Tip: You should typically create a single Container instance for the whole application (one instance per app domain); Container instances are thread-safe.
Warning: Registering types in a container instance should be done from one single thread. Although requesting instances from the container is thread-safe, registration is not.
Warning: Do not create an infinite number of Container instances (such as one instance per request). This will drain the performance of your application. The framework is optimized for using a limited number of Container instances. Creating and initializing a container instance has a lot of overhead, but is extremely fast once initialized.
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 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 Simple Injector for a specific technology, please see the Integration Guide.
The usage of 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>(Lifestyle.Transient);
        container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Singleton);

        // 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.

Resolving instances

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));

Configuring 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 scenarios. Here are the most common scenarios 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>();

// Alternatively you can supply a Lifestyle with the same effect.
container.Register<IUserService, RealUserService>(Lifestyle.Singleton);

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

// Alternatively you can supply the singleton Lifestyle with the same effect.
container.Register<IUserRepository>(() => UserRepFactory.Create("some constr"), Lifestyle.Singleton);

// 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>();

// Alternatively you can supply the transient Lifestyle with the same effect.
container.Register<IHandler<MoveCustomerCommand>, MoveCustomerHandler>(Lifestyle.Transient);

// 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;
});

container.Register<IHandler<MoveCustomerCommand>>(() => { ... }, Lifestyle.Transient);
// Alternatively you can supply the transient Lifestyle with the same effect.
// 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:
Simple Injector contains several methods for registration and resolving collections of types. Here are some examples:
// Configuration
// Registering a list of instances that will be created by the container.
// Supplying a collection of types is the preferred way of registering collections.
container.RegisterAll<ILogger>(typeof(IMailLogger), typeof(SqlLogger));

// 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);

// Usage
var loggers = container.GetAllInstances<ILogger>();
Note: When no instances are registered using RegisterAll, Container.GetAllInstances will always return an empty list.
Just as with normal types, 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>(typeof(MailLogger)), typeof(SqlLogger));
container.RegisterSingle<IService, Service>();

// Usage
var service = container.GetInstance<IService>();
service.DoStuff();
The RegisterAll overloads that take a collection of Type instances, forward the creation of those types to the container, which means that the same rules apply to them. Take a look at the following configuration:

// Configuration
container.Register<MailLogger>(Lifestyle.Singleton);
container.Register<ILogger, FileLogger>();

container.RegisterAll<ILogger>(typeof(MailLogger)), typeof(SqlLogger), typeof(ILogger));
When the registered collection of ILogger instance is resolved, the container will resolve each and every one of them using their configuration. When no such registration exists, the type is created with the Transient lifestyle (which means, that a new instance is created every time the returned collection is iterated). The MailLogger type however, has an explicit registration and since it is registered as Singleton, the resolved ILogger collections will always have the same instance.

Since the creation is forwarded, also abstract types can be registered using RegisterAll. In this case the ILogger type itself is registered using RegisterAll. This seems like a recursive definition, but it will work nonetheless. In this particular case you could imagine this to be a registration with a default ILogger registration, that is included in the collection of ILogger instances as well.

While resolving collections is useful and also works with automatic constructor injection, the registration of composites is preferred over the use of collections as constructor arguments in application code. 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.

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 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.
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, 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 Simple Injector please visit the following links:
  • The Simple Injector and object lifetime management page explains how to configure lifestyles such as transient, singleton, and many others.
  • See the Integration Guide for more information about how to integrate Simple Injector into your specific application framework.
  • For more information about dependency injection in general, please visit this page on Stackoverflow.
  • If you have any questions about how to use Simple Injector or about dependency injection in general, the experts at Stackoverflow.com are waiting for you.
  • For all other Simple Injector related question and discussions, such as bug reports and feature requests, the Simple Injector discussion forum will be the place to start.

Last edited Feb 10 at 8:58 AM by dot_NET_Junkie, version 29