Click here to Skip to main content
Click here to Skip to main content

Simple Injector

, 31 Jul 2012
Rate this:
Please Sign up or sign in to vote.
The easiest Inversion of Control framework in town.

Introduction

The Simple Injector is an easy-to-use Inversion of Control (IoC) library for .NET and Silverlight. It solely supports code-based configuration, and is an ideal starting point for both developers unfamiliar with larger IoC / DI libraries and for developers who seek to apply the SOLID design principles to their applications. Many development teams are already using Simple Injector in their production environments today with great satisfaction.

This article will describes the rationale behind the Simple Injector, the usage, and the actual implementation. This article will not explain the concept of Dependency Injection (DI). If you are new to the concept, there are many good articles describing DI, but Wikipedia is a good starting point.

Background

Many development teams I help have legacy code bases with few or no unit tests. As you can imagine, the complexity makes it hard to add new features and fix existing bugs. Changing the course is often not easy, because the developers need to learn a whole new bag of tricks. One of those tricks is unit testing, and inextricably connected with that is loosely coupled code. In my opinion, the best way to achieve loosely coupled code is by applying the Dependency Injection pattern.

To get teams on the road quickly, I often want to do the simplest thing that could possibly work. For that reason, I've been annoyed with the complexity of the popular Dependency Injection frameworks. The concepts of Inversion of Control, Dependency Injection, and good RTM unit tests are by itself hard enough to grasp for many developers. Learning to work with, and configure several different frameworks (such as frameworks for presentation, logging, validation, workflow, security, O/RM, and Inversion of Control) at the same time makes it even harder.

For this reason, I started the Simple Injector project. It's yet another Inversion of Control library for .NET. The key features are its performance, simplicity and ease of migration to other, more feature-rich, IoC frameworks. This makes it especially useful for development teams unfamiliar with one of the existing Inversion of Control frameworks (although I've seen developers switch to the Simple Injector, because of features other frameworks are lacking). Development teams can start using the Simple Injector and replace it with another IoC framework later on when needed, without having to alter any production code. For the lifetime of many projects however, the Simple Injector will be sufficient, because although simple, the available extensibility points enable even the most advanced scenarios.

Usage

A good practice is to minimize the dependency between your application and the IoC framework. This increases the maintainability and testability 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, which means that you define all dependencies of a class as parameters of 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).

With that in mind, here is an example of how to use the Simple Injector Container class to resolve an instance:

IUserService repository = container.GetInstance<IUserService>();

Configuring the Simple Injector is done in the startup path of the application (in DI terminology: the Composition Root), as can be seen below. In this example, you see how the Simple Injector is configured in the Application_Start event of the global.asax of an ASP.NET Web Forms application.

using SimpleInjector;

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

    protected void Application_Start(object sender, EventArgs e) 
    {
        Bootstrap();
    }

    private static void Bootstrap()
    {
        // 1. Create a new Simple Injector container
        var container = new Container();

        // 2. Configure the container (register)
        
        // Register a new UserService instance to be returned, each time an
        // IUserService is requested.
        container.Register<IUserService, UserService>();
        
        // Register that the same SqlUserRepository instance will be returned,
        // each time an IUserRepository is requested (in this case
        // SqlUserRepository must be thread-safe).
        container.RegisterSingle<IUserRepository, SqlUserRepository>();

        // Register a delegate that knows how to create a new
        // DatabaseLogger when a ILogger is requested.
        container.Register<ILogger>(() => new DatabaseLogger
        {
            Severity = LogLevel.Information,
            ConnectionString = ConfigurationManager.AppSettings["Logger"]
        });        
        
        // 3. Optionally, check the configuration for correctness, such 
        //    as missing dependencies and recursive dependency graphs.
        //    This will prevent the application from starting in case of an error.
        container.Verify();

        // 4. Store the container for use by the application 
        Global.Container = container;
    }
}

Although the previous example is specific to the use of the Simple Injector in a ASP.NET Web Forms application, Simple Injector itself is technology agnostic. There is an integration section on the CodePlex site, that describes how to integrate Simple Injector with your technology of choice.

The Simple Injector uses automatic constructor injection (a.k.a. auto-wiring), which means that it will look at the arguments of the public constructor of a concrete type to see which dependencies it contains and injects instances for those types into that constructor. This holds both for concrete types that haven't been registered, and for types that have been registered using a generic Register overload, such as we've seen in the container.Register<IUserService, UserService>() call from the previous code snippet. Look for instance, at the definition of the UserService class that we registered in the previous code snippet:

public class UserService : IUserService
{
    private readonly IUserRepository repository;
    private readonly ILogger logger;

    public UserService(IUserRepository repository, ILogger logger)
    {
        this.repository = repository;
        this.logger = logger;
    }
}

Because this class is concrete and has a single public constructor, the container knows how to create a UserService when we use the following registration:

container.Register<IUserService, UserService>();

And even when no registration has been made, a new instance can still be created by directly requesting an instance of that concrete type from the container:

container.GetInstance<UserService>()

Although the type doesn't need to be registered, its dependencies (IUserRepository and ILogger) will have to be registered, simply because they are not concrete types.

Please note that auto-wiring is only possible when a type contains a single public constructor. Types with multiple public constructors cannot be created by the container. This restriction is chosen deliberately, because all IoC frameworks have different strategies when it comes to selecting a constructor to inject. This limitation will make it easier to migrate to another framework later on if needed, and forces developers to have a clean design.

Besides this, the Simple Injector has other restrictions, such as the lack of overriding the auto-wiring by explicitly mapping unresolvable parameters. While this feature has its use, it steers developers away from clean application design and often introduces fragile configuration, that breaks after refactoring.

Although these features are not supported out of the box (for good reason), Simple Injector contains extension points that allow these features to be added.

Besides the limit on constructor injection, there are some advanced scenarios that the Simple Injector does not support out of the box. While these restrictions will lead to an application with a very clean dependency inversion strategy, it can (and probably will) influence the design of your application. In case of an existing code base, it could require you to make more changes to your code, or add custom code that hooks onto the extension points, than it could when using one of the other DI frameworks. This is something you might need to take into consideration. However, keep in mind that you should always strive towards a clean application design (even for legacy applications), since a clean and flexible design (by following the SOLID principles for instance) will help in getting an maintainable application.

But don't be fooled! Many advanced scenarios, such as batch registration, registration of open generic types and registration of open generic decorators are supported out of the box by including the SimpleInjector.Extensions.dll assembly. Features such as Lifetime Scoping and Per Web Request (which allow support for the Register Resolve Release pattern) are supported by including feature assemblies (or NuGet packages). Other scenarios, such as context-based injection, per-thread lifestyle, interception, and contravariance support are possible and given as examples on Advanced Scenarios wiki page.

Simple Injector allows the possibility to replace Expression objects after they are created by the container, and just before they are compiled to Func<T> delegates. I tried really hard to think of a scenario that now still can't be implemented in the Simple Injector, but the possibilities of this simple extension point are endless. With this mechanism in place, features such as context-based injection can be added.

Please visit the Simple Injector home page to see more code examples.

Show Me The Code, Man!

The Simple Injector is completely designed around .NET 2.0 Generics and .NET 3.5 Func<T> delegates and Expression trees. This allows type safe code-based configuration. Internally, the container contains a dictionary that stores the registrations and uses .NET 3.5 Expression trees. In the next few paragraphs, I'll take you through some interesting parts of the code base of the core library. Starting at the easy stuff and ending at the slightly more advanced stuff. Let's start with the part of the Simple Injector API that is used for setting up the container.

public class Container : System.IServiceProvider
{
    // Registering an instance per request (transient)
    public void Register<TConcrete>();   
    public void Register<TService, TImplementation>();
    public void Register<TService>(Func<TService> instanceCreator);
    
    // Registering a single instance (singleton)
    public void RegisterSingle<TConcrete>();   
    public void RegisterSingle<TService, TImplementation>();
    public void RegisterSingle<TService>(TService instance);    
    public void RegisterSingle<TService>(Func<TService> instanceCreator);
    
    // Registering an initializer (useful for property injection)
    public void RegisterInitializer<TService>(Action<TService> initializer);
    
    // Registering a set of multiple instances
    public void RegisterAll<TService>(IEnumerable<TService> collection);
    public void RegisterAll<TService>(params TService[] collection);
    
    public void Verify();

    // Hook to allow unregistered type resolution.
    public event EventHandler<UnregisteredTypeEventArgs> ResolveUnregisteredType;
    
    // Hook to intercept the way instances are created by the container.
    public event EventHandler<ExpressionBuiltEventArgs> ExpressionBuilt;
    
    // Other methods omitted.
}

Type Registration

When we take a peek at how things are working under the covers, you'll notice that most things are actually quite simple. Let's, for instance, take a look at the Register<TService>(Func<TService>) method:

public void Register<TService>(Func<TService> instanceCreator)
{
    // error checking omitted.

    this.registrations[typeof(TService)] = 
        new FuncInstanceProducer<TService>(instanceCreator);    
}

Did you notice that the implementation is just a one-liner? The code simply wraps the supplied Func<T> delegate in a FuncInstanceProducer and adds that instance to the registrations dictionary with the type of TService as its key. The registrations dictionary accepts IInstanceProducer values; an interface that functions as an abstraction over objects that know how to produce instances of a given service type.

Before looking at the FuncInstanceProducer class, let's first look at the IInstanceProducer interface:

public interface IInstanceProducer
{
    object GetInstance();

    Expression BuildExpression();
}

The interface contains two methods. The first object GetInstance() method is one you probably expected. The container uses this method to request a registered producer to return an instance. How a producer does this -of course- depends on the implementation. The second Expression BuildExpression(), on the other hand, might raise some eyebrows. The container uses this method to ask a producer to build a System.Linq.Expressions.Expression that describes the intent to get that instance. The container uses these Expressions to compile highly performant constructor invocations. But more on this later.

FuncInstanceProducer implements IInstanceProducer and wraps the supplied Func<T> delegate. Here is the code for the FuncInstanceProducer:

internal sealed class FuncInstanceProducer<T> : IInstanceProducer
{
    // NOTE: Code for recursive dependency graph detection omitted.
    internal FuncInstanceProducer(Func<T> instanceCreator)
    {
        this.instanceCreator = instanceCreator;
    }

    object IInstanceProducer.GetInstance()
    {
        return this.GetInstance();
    }

    Expression IInstanceProducer.BuildExpression()
    {
        return Expression.Call(Expression.Constant(this),
            this.GetType().GetMethod("GetInstance"), new Expression[0]);
    }

    public T GetInstance()
    {
        T instance;

        try
        {
            instance = this.instanceCreator();
        }
        catch (Exception ex)
        {
            throw new ActivationException(StringResources
                .DelegateForTypeThrewAnException(typeof(T), ex), ex);
        }

        if (instance == null)
        {
            throw new ActivationException(StringResources
                .RegisteredDelegateForTypeReturnedNull(typeof(T)));
        }

        return instance;
    }
}

As you can see, FuncInstanceProducer does not contain that much code. About half of the code is about error checking and reporting useful error messages to the user. What you might already have noticed is that the IInstanceProducer interface specifies the GetInstance method to return object. Because the container is able to return all kinds of objects, we need to work with the base type of the CLR type hierarchy. Casting is therefore a necessarily evil. When you look closely at the BuildExpression method however, you see that the method FuncInstanceProducer builds an expression that calls the generic T GetInstance() method instead of calling the object IInstanceProducer.GetInstance() method. In other words, when the type presented by FuncInstanceProducer is not a root type, but a dependency that will be injected using constructor injection, the cast can be skipped (and other IInstanceProducer implementations are even able to optimize even further).

As you saw, FuncInstanceProducer contains some clever tricks to optimize performance, while still being a simple little class. Another interesting producer is FuncSingletonInstanceProducer<T>, which is used by RegisterSingle<T>(Func<T>):

public void RegisterSingle<TService>(Func<TService> instanceCreator)
    where T : class
{
    // error checking omitted.
    
    this.registrations[typeof(TService)] =
        new FuncSingletonInstanceProducer<TService>(instanceCreator);
}

This method is, just like the Register method, a one liner. The spice is again in the instance producer; in this case, FuncSingletonInstanceProducer<T>:

internal sealed class FuncSingletonInstanceProducer<T>
    : IInstanceProducer where T : class
{
    // NOTE: Recursive dependency graph detection omitted.
    private Func<T> instanceCreator;
    private T instance;

    internal FuncSingletonInstanceProducer(Func<T> instanceCreator)
    {
        this.instanceCreator = instanceCreator;
    }

    public object GetInstance()
    {
        if (this.instance == null)
        {
            lock (this)
            {
                if (this.instance == null)
                {
                    this.instance = this.GetInstanceFromCreator();
                }
            }
        }

        return this.instance;
    }

    Expression IInstanceProducer.BuildExpression()
    {
        return Expression.Constant(this.GetInstance());
    }

    private T GetInstanceFromCreator()
    {
        T instance;

        try
        {
            instance = this.instanceCreator();
        }
        catch (Exception ex)
        {
            throw new ActivationException(StringResources
                .DelegateForTypeThrewAnException(typeof(T), ex), ex);
        }

        if (instance == null)
        {
            throw new ActivationException(StringResources
                .DelegateForTypeReturnedNull(typeof(T)));
        }

        this.instanceCreator = null;

        return instance;
    }
}

Just like the FuncInstanceProducer class, FuncSingletonInstanceProducer wraps a Func<T> delegate. The class will ensure that the delegate is not called more than once by using a lock statement. The class implements a double-checked lock to prevent unnecessary locking from occurring after the instance is constructed.

Also note the implementation of the BuildExpression() method. See how this method simply calls the GetInstance method and wraps it in a Expression.Constant? This means that the reference to the object is used as a constant by the container when building the delegate that constructs a type that depends on this type. We can do this, because RegisterSingle should always return the same object. This will result in extremely fast object construction.

What the previous examples have shown is that registration of types in the container itself is in fact nothing more than the definition of the intend to produce such an instance. There is no compilation of delegates going on during the registration phase. Not only does this make the code pretty easy to grasp, but postponing compilation until after the registration phase is especially a conscious design decision to improve performance. By design, users are allowed to register types in any order they like. This means that when we would compile a delegate directly after a type was registered, chances are that at that point not all dependent types are registered. This means that we don't know with what lifetime that type would be registered, and this would force us to compile a delegate that would call the container's GetInstance<T> method for every dependency instead of using the optimizations that we saw before.

The part of the container that we've looked at is the registration part. As I said, compilation of delegates is postponed and done after the registration phase. The container is able to compile delegates that construct graphs of objects by looking at the parameter types in a type's constructor, a technique which is known as automatic constructor injection or auto-wiring. We will look at this shortly, but let's first take a look at what's happening when an instance of a given type is requested.

Instance Retrieval

The Container class implements, among others, the GetInstance<T>() method. This method delegates the retrieval to the private GetInstanceForType(Type) method, that looks like this:

private object GetInstanceForType(Type serviceType)
{
    IInstanceProducer instanceProducer = 
        this.GetInstanceProducerForType(serviceType);

    if (instanceProducer != null)
    {
        return instanceProducer.GetInstance();
    }

    throw new ActivationException(StringResources
        .NoRegistrationForTypeFound(serviceType));
}

Retrieval of the instance producer is extracted to the GetInstanceProducerForType method, which looks like this:

internal IInstanceProducer GetInstanceProducerForType(Type serviceType)
{
    IInstanceProducer instanceProducer;
    
    var snapshot = this.registrations;
    
    if (!snapshot.TryGetValue(serviceType, out instanceProducer))
    {
        instanceProducer = this.BuildInstanceProducerForType(serviceType);
    
        if (instanceProducer != null)
        {
            this.RegisterInstanceProducer(instanceProducer, serviceType, snapshot);
        }
    }
    
    return instanceProducer;
}

Some interesting things are happening here. First of all, instead of reusing the registrations dictionary that holds all the IInstanceProducer instances, the GetInstanceProducerForType method stores a copy of the reference to that dictionary in the snapshot argument. During the executing of that method, the snapshot is reused. While this seems odd and unnecessary, this actually helps in making the code thread-safe without using locks (bear with me, as I'll try to explain in a second). Next, the method uses the snapshot to load an instance producer of the given serviceType. When the snapshot dictionary contains the instance producer for the given serviceType, the method will return that producer and GetInstanceForType will invoke its GetInstance method. When there is no registration for the given serviceType, GetInstanceProducerForType will try to create a new instance producer for that type. There are a few scenarios where the container can create an instance producer after the registration phase. The most common scenario is the creation of unregistered concrete types (another scenario is unregistered type resolution using the ResolveUnregisteredType event, but discussion of that event is outside the scope of this article). The container is able to create instances of concrete types and it will build an instance producer for that. When such a producer is created, it will be stored in the registrations dictionary.

While I think most of this sounds very plausible, the trick with the reference copy might scare some of you. Why should making a copy of -only- a reference make the container thread-safe? I will try to explain.

The container is 'locked down' at the moment the first instance is requested from the container. This means that it is impossible for a user to register new types after this point. This forces users to configure the container in one place (the startup path of the application), because changing the container during the application's lifetime just isn't a wise thing to do, or it is at least a scenario that is not suited for this simple IoC library. However, it also makes it much easier to create a lock-free -and therefore faster- container.

Although the container is locked down when the first instance is requested, the dictionary that holds the registrations must still be able to change. One of the reasons the container needs to change is the the retrieval of unregistered concrete types. As I've explained, when an unregistered concrete type is requested, the container will construct a delegate for the construction of a new instance of that concrete type by looking at its public constructor. This delegate is cached for obvious performance reasons, but this however does mean the particular registrations dictionary has to be updated.

Adding new values to that dictionary is done by replacing the old dictionary with a completely new one, thus using the dictionary as an immutable type and replacing the reference. Therefore, as long as we stick to using that same reference during the execution of a single request, we know the dictionary isn't going to change and we don't need a lock. For this reason, the GetInstanceProducerForType method holds on to this reference. In other words, the container is effectively making a snapshot of its state to prevent seeing any changes to the world around it!

Note that this type of reference-swapping thread-safety isn't a silver bullet; it isn't always suitable. You must be able to accept the fact that updates can get lost. Look for instance what happens when two threads request each a different unregistered concrete type at the same time. In that scenario, both threads will use the same registrations instance. During the execution, they will each construct their own IInstanceProducer for these concrete types. They create a copy of the registrations dictionary and add the new producer to their own copy. At the end of the call, both threads will override the reference to the old registrations instance with their own copy. Since both now have their own (and different) version, the changes of one of the threads will get lost. The important thing to note however is: Although one of the threads will lose; since we're updating a single reference, we won't corrupt any state.

Why this reference-swapping technique is still suitable in this scenario however, is simple. Loosing an update is not an issue, because the missing instance producer will be regenerated the next time such an instance is requested. What we lose in that scenario is a bit of (one-time) performance, because the producer and the delegate it wraps have to be regenerated. The assumption however is, that this type of race conditions will be rare enough, that the performance impact is negligible and finite. It is assumed to be finite, because at one time during the lifetime of the application, all types the application can request will be in the cache. Users that work on applications that can't afford this cost during runtime (or the cost of extra pressure on the garbage collection) could simply register all concrete types upfront and call Verify after the configuration phase, because this will trigger the compilation of delegates for all registered types.

Automatic Constructor Injection

The last thing I like to discuss is how the Simple Injector is able to do automatic constructor injection. The Container class forwards construction of the delegates to the internal DelegateBuilder class. This class (consisting of just 16 lines of code) is able to create a delegate that invokes the constructor of that concrete type and loads any dependencies directly without further intervention from the container. For instance, let's take a look again at the concrete UserService class we've seen before:

public class UserService : IUserService
{
    private readonly IUserRepository repository;
    private readonly ILogger logger;

    public UserService(IUserRepository repository, ILogger logger)
    {
        this.repository = repository;
        this.logger = logger;
    }
}

DelegateBuilder can effectively compile a delegate that creates a new UserService. What exact delegate will be compiled depends on the way its dependencies are configured. Let's say that IUserRepository is configured as a singleton and ILogger is configured with container.Register<ILogger, RealLogger>() (and let's assume that RealLogger has a default constructor). In that case, the compiled Func<T> delegate for creating a IUserService would look like this:

() => new UserService(repository, new RealLogger());

The variable repository is a constant that references the single SqlUserRepository and note how the container effectively generated new RealLogger() call into the constructor. Often registrations as the one we have seen for the ILogger interface end up as direct calls to other constructors.

Because the container is injecting dependencies recursively, it is able to build complex graphs of objects. DelegateBuilder uses .NET 3.5's Expression class to construct an expression and compile it down to a delegate. This is done in a few simple steps, lined out in the Build method:

internal static Func<TConcrete> Build<TConcrete>(Container container)
{
    var newExpression = BuildExpression(container, typeof(TConcrete));

    var newServiceTypeMethod = Expression.Lambda<Func<TConcrete>>(
        newExpression, new ParameterExpression[0]);

    return newServiceTypeMethod.Compile();
}

internal static Expression BuildExpression(Container container, Type concreteType)
{
    Helpers.ThrowActivationExceptionWhenTypeIsNotConstructable(concreteType);

    var constructor = concreteType.GetConstructors().Single();

    var constructorArgumentCalls =
        from parameter in constructor.GetParameters()
        select BuildParameterExpression(container, concreteType, 
            parameter.ParameterType);

    return Expression.New(constructor, constructorArgumentCalls.ToArray());
}

private static Expression BuildParameterExpression(Container container,
    Type concreteType, Type parameterType)
{
    var instanceProducer = container.GetInstanceProducerForType(parameterType);

    if (instanceProducer == null)
    {
        throw new ActivationException(StringResources
            .ParameterTypeMustBeRegistered(concreteType, parameterType));
    }

    return instanceProducer.BuildExpression();
}

The Build method gets the public constructor of the type. Next, the method will build a list of Expression objects that represent the production of dependencies; one for each constructor argument (this is where IInstanceProducer.BuildExpression() comes in). Next, it will build a new lambda expression that expresses the intent to invoke the constructor with the supplied constructorArgumentCalls. The last step is to compile the lambda expression to a Func<T> delegate by calling Expression.Compile (or to return directly as expression so it can be part of a bigger expression that will be compiled to a single delegate).

Wow! Did you see how easy this became by using the new .NET Expression API? Imagine doing this with Lightweight Code Generation using Reflection.Emit. That would have been quite painful.

But it even gets more exiting. The Simple Injector allows you to get notified by the container every time an Expression instance is created and it allows you to swap that instance with a different one, just before the container compiles that delegate to a Func<T> delegate. Although fiddling around with expression trees can be a bit daunting sometimes, it allows you to completely change the way types are created by the container. Take for instance this extension method:

public static void Register<TService, TImplementation>(
    this Container container, IConstructorSelector selector)
    where TService : class
{
    container.Register<TService>(() => null);

    container.ExpressionBuilt += (sender, e) =>
    {
        if (e.RegisteredServiceType == typeof(TService))
        {
            var ctor = selector.GetConstructor(typeof(TImplementation));
            
            var parameters = 
                from parameter in ctor.GetParameters()
                let type = parameter.ParameterType
                select container.GetRegistration(type, true).BuildExpression());

            e.Expression = Expression.New(ctor, parameters);
        }
    };
}

public interface IConstructorSelector
{
    ConstructorInfo GetConstructor(Type type);
}

This example looks complex, but it does show the possibilities of this approach. This particular extension method allows you to register a type containing multiple public constructors (or with no public constructor at all), which is a feature that is left out of the Simple Injector. When the ExpressionBuilt event gets raised, the hooked delegate will replace Expression of the original (fake) registration with an Expression that describes the intend of creating a new instance using the retrieved constructor.

Don't worry if you don't get this. This callback mechanism is intended for advanced scenarios and many usable (copy-pastable) examples are given on the CodePlex site. The change of you having to write your own are small. However, it does show how cool the Simple Injector is. This simple extension point enables many advanced scenarios, without the need of a complex API and without sacrificing performance. Simple Injector is currently the only DI container that allows you to fiddle around with Expression trees (it also allows you to visualize the actual expression the container generated for a given registration, which can be useful for debugging and profiling).

Conclusion 

As you've seen, while there are a few clever design decisions made, most of the code is actually really straightforward. One of the parts I deliberately left out of the article is the error checking (although you've seen some of it). Handling and communicating errors in an effective way is crucial for good usability. While it's a lot of work to get this right, I didn't think it wouldn't be a very interesting thing to show. If you are interested in this, or anything else I didn't discuss (such as unregistered type resolution, property injection, and cyclic dependency graph detection), please take a look at the source code. You may reuse and abuse the code. The license permits it. If you're not using Dependency Injection in your application today, this is the time to start looking at it. Read more about Dependency Injection and try the Simple Injector out.

Since the first stable release in April 2011, Simple Injector has been used in many production environments with success. We regularly publish new stable production-ready releases, but your feedback is still very welcome. What do you think of the current API? Can we make it even simpler? Do you miss anything? Please let us know.

Happy injecting!

History

  • 31th July, 2012: Text updated for Simple Injector v1.5.0.
  • 27th May, 2012: Text updated for Simple Injector v1.4.2.
  • 26th February, 2012: Text updated for Simple Injector v1.4 and broken links fixed.
  • 31st December, 2011: Text updated for Simple Injector v1.3.1 and incorrect links fixed.
  • 13th December, 2011: Text updated for Simple Injector v1.3.
  • 30th September, 2011: Text updated for Simple Injector v1.2.
  • 24th May, 2011: Text updated for Simple Injector v1.1.
  • 26th April, 2011: Text updated for Simple Injector v1.0.
  • 28th February, 2011: Text updated for v0.14.
  • 17th January, 2011: Text updated for v0.13.
  • 27th November, 2010: Text updated for v0.12.
  • 3rd November, 2010: Text updated for v0.11.
  • 25th September, 2010: Text updated for v0.10.
  • 9th September, 2010: Text updated for v0.9 and a thorough description of the actual implementation added.
  • 28th March, 2010: Text updated for v0.7.
  • 12th February, 2010: Text updated for v0.6.
  • 20th January, 2010: Updated text based on feedback from Bryan Watts.
  • 7th January, 2010: Initial post.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

You may also be interested in...

About the Author

The .NET Junkie
Software Developer (Senior)
Netherlands Netherlands
I'm a freelance developer from the Netherlands, working with .NET technology on a daily basis, and officially diagnosed as a workaholic.
Follow on   Twitter

Comments and Discussions

 
Questionperformance PinmemberCarelAgain28-Jun-14 1:27 
QuestionForgot to vote my 5 PinmemberWang Chun Hsun4-May-14 22:02 
QuestionGood design but lacking features PinmemberWang Chun Hsun4-May-14 22:01 
AnswerRe: Good design but lacking features PinpremiumThe .NET Junkie5-May-14 1:18 
GeneralRe: Good design but lacking features PinmemberWang Chun Hsun5-May-14 3:53 
QuestionCode Required PinmemberPaul85224-Jan-13 19:52 
AnswerRe: Code Required PinmemberKalev Rebane13-May-13 10:53 
AnswerRe: Code Required PinmemberThe .NET Junkie13-May-13 22:07 
GeneralMy vote of 5 PinmemberDaniel Lo Nigro4-Dec-12 16:17 
Question[Awesomeness] happens in codeproject. Pinmemberring_031-Jul-12 20:14 
AnswerRe: [Awesomeness] happens in codeproject. PinmemberThe .NET Junkie31-Jul-12 21:05 
AnswerRe: [Awesomeness] happens in codeproject. PinpremiumThe .NET Junkie5-May-14 3:11 
GeneralMy vote of 5 Pinmembermanoj kumar choubey20-Jul-12 1:33 
GeneralMy vote of 5 PinmemberMohammad A Rahman26-May-12 15:53 
GeneralMy vote of 5 PinmvpKanasz Robert18-Jan-12 21:44 
Questionvery good PinmemberCIDev14-Dec-11 4:03 
QuestionThis is well cool PinmvpSacha Barber13-Dec-11 3:43 
AnswerRe: This is well cool PinmemberThe .NET Junkie13-Dec-11 10:49 
GeneralMy vote of 5 PinmemberRob Lyndon2-Oct-11 12:55 
GeneralMy vote of 5 Pinmembermbarbac7-Jun-11 21:56 
GeneralMy vote of 5 Pinmembermbarbac7-Jun-11 21:55 
GeneralMy vote of 5 Pinmemberseesharper26-May-11 5:12 
GeneralNice! PinmemberMember 45586626-May-11 2:17 
GeneralWorks on CF? PinmemberLoic Berthollet25-May-11 21:58 
GeneralRe: Works on CF? PinmemberThe .NET Junkie26-May-11 0:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140827.1 | Last Updated 31 Jul 2012
Article Copyright 2010 by The .NET Junkie
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid