Quick Start

Overview

The goal of Simple Injector is to provide .NET application developers with an easy, flexible, and fast Inversion of Control library that promotes best practice to steer developers towards the pit of success.

Many of the existing DI libraries have a big complicated legacy API or are new, immature, and lack features often required by large scale development projects. Simple Injector fills this gap by supplying a simple implementation with a carefully selected and complete set of features. File and attribute based configuration methods have been abandoned (they invariably result in brittle and maintenance heavy applications), favoring simple code-based configuration instead. This is enough for most applications, requiring only that the configuration be performed at the start of the program. The core library contains many features and allows almost any advanced scenario.

The following platforms are supported:

  • .NET 4.5 and up.

  • .NET Standard including:

    • Universal Windows Programs.

    • Mono.

    • .NET Core.

    • Xamarin.

Simple Injector is carefully designed to run in partial / medium trust, and it is fast; blazingly fast.

Getting started

The easiest way to get started is by installing the available NuGet packages.

A Quick Example

Dependency Injection

The general idea behind Simple Injector (or any DI library for that matter) is that you design your application around loosely coupled components using the Dependency Injection pattern while adhering to the Dependency Inversion Principle. Take for instance the following CancelOrderHandler class:

public class CancelOrderHandler
{
    private readonly IOrderRepository repository;
    private readonly ILogger logger;
    private readonly IEventPublisher publisher;

    // Use constructor injection for the dependencies
    public CancelOrderHandler(
        IOrderRepository repository, ILogger logger, IEventPublisher publisher)
    {
        this.repository = repository;
        this.logger = logger;
        this.publisher = publisher;
    }

    public void Handle(CancelOrder command)
    {
        this.logger.Log("Cancelling order " + command.OrderId);
        var order = this.repository.GetById(command.OrderId);
        order.Status = OrderStatus.Cancelled;
        this.repository.Save(order);
        this.publisher.Publish(new OrderCancelled(command.OrderId));
    }
}

public class SqlOrderRepository : IOrderRepository
{
    private readonly ILogger logger;

    // Use constructor injection for the dependencies
    public SqlOrderRepository(ILogger logger)
    {
        this.logger = logger;
    }

    public Order GetById(Guid id)
    {
        this.logger.Log("Getting Order " + order.Id);
        // Retrieve from db.
    }

    public void Save(Order order)
    {
        this.logger.Log("Saving order " + order.Id);
        // Save to db.
    }
}

The CancelOrderHandler class depends on the IOrderRepository, ILogger and IEventPublisher interfaces. By not depending on concrete implementations, you can test CancelOrderHandler in isolation. But ease of testing is only one of a number of things that Dependency Injection gives us. It also enables you, for example, to design highly flexible systems that can be completely composed in one specific location (often the startup path) of the application.

Please be aware that it is not this documentation’s intention to teach you about the fundamentals of Dependency Injection. To gain more in-depth knowledge about the fundamentals of Dependency Injection and the design patterns and principles surrounding it, the book Dependency Injection Principles, Practices, and Patterns is an excellent place to start. This book is co-authored by Simple Injector’s lead maintainer.

Introducing Simple Injector

Using Simple Injector in a simple Console application, the configuration of the application using the CancelOrderHandler and SqlOrderRepository classes shown above, might look something like this:

using SimpleInjector;

static class Program
{
    static readonly Container container;

    static Program()
    {
        // 1. Create a new Simple Injector container
        container = new Container();

        // 2. Configure the container (register)
        container.Register<IOrderRepository, SqlOrderRepository>();
        container.Register<ILogger, FileLogger>(Lifestyle.Singleton);
        container.Register<CancelOrderHandler>();

        // 3. Verify your configuration
        container.Verify();
    }

    static void Main(string[] args)
    {
        // 4. Use the container
        var handler = container.GetInstance<CancelOrderHandler>();

        var orderId = Guid.Parse(args[0]);
        var command = new CancelOrder { OrderId = orderId };

        handler.Handle(command);
    }
}

The given configuration registers implementations for the IOrderRepository and ILogger interfaces, as well as registering the concrete class CancelOrderHandler. The code snippet shows a few interesting things. First of all, you can map concrete instances (such as SqlOrderRepository) to an interface or base type (such as IOrderRepository). In the given example, every time you ask the container for an IOrderRepository, it will always create a new SqlOrderRepository on your behalf (in DI terminology: an object with a Transient lifestyle).

The second registration maps the ILogger interface to a FileLogger implementation. This FileLogger is registered with the Singleton lifestyle—only one instance of FileLogger will ever be created by the Container.

Further more, you can map a concrete implementation to itself (as shown with the CancelOrderHandler). This registration is a short-hand for the following registration:

container.Register<CancelOrderHandler, CancelOrderHandler>();

This basically means, every time you request a CancelOrderHandler, you’ll get a new CancelOrderHandler.

Using this configuration, when a CancelOrderHandler is requested, the following object graph is constructed:

new CancelOrderHandler(
    new SqlOrderRepository(
        logger),
    logger);

Note that object graphs can become very deep. What you can see is that not only CancelOrderHandler contains dependencies—so does SqlOrderRepository. In this case SqlOrderRepository itself contains an ILogger dependency. Simple Injector will not only resolve the dependencies of CancelOrderHandler but will instead build a whole tree structure of any level deep for you.

And this is all it takes to start using Simple Injector. Design your classes around the SOLID principles and the Dependency Injection pattern (which is actually the hard part) and configure them during application initialization. Some frameworks (such as ASP.NET MVC) will do the rest for you, other frameworks (like ASP.NET Web Forms) will need a little bit more work. See the Integration Guide for examples of integrating with many common frameworks.

Please go to the Using Simple Injector section in the documentation to see more examples.

More information

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