Note: this documentation is specific for Simple Injector version 2.0 and up. Look here for 1.x specific documentation.
Simple Injector and Object Lifetime Management
Object Lifetime Management is the concept of controlling the number of instances a configured service will have and the duration of the lifetime of those instances. In other words, it allows you to determine how returned instances are cached. Most IoC frameworks have sophisticated mechanisms for lifestyle management. The
Simple Injector has built-in support for the most common lifestyles. The two default lifestyles (transient and singleton) are part of the core library, and other lifestyles are part of some of the extension and integration packages. These built-in lifestyles should fit for about 99% of the cases. For other cases, custom lifestyles can be created.
Below is a list of the most common lifestyles with code examples of how to configure them using the
Simple Injector. This page discusses the following lifestyles:
Transient
For each request (both for calls to GetInstance<T> and instances as part of an object graph), a new instance of the service type will be created.
The next example instantiates a new
IService instance on each call, while leveraging the power of
automatic constructor injection.
container.Register<IService, RealService>(Lifestyle.Transient);
// Alternatively, you can use the following short cut
container.Register<IService, RealService>();
The next example instantiates a new
RealService instance on each call by using a delegate.
container.Register<IService>(() => new RealService(new SqlRepository()), Lifestyle.Transient);
Note: registration using Register<TService, TImplementation>() is the recommended approach. It is easier, leads to less fragile configuration, and results in faster retrieval than registration using a Func<T> delegate. Try the former approach before reverting to using delegates where possible.
Also note that this construct will only work while registering types by a base type. For concrete transient types, no registration is needed. The concrete type will automatically be created once requested:
container.GetInstance<RealService>();
When you have a type that you want to be created using automatic constructor injection, but need some configuration that can't be done using constructor injection, you can use the
RegisterInitializer method. It takes an
Action<T> delegate:
container.RegisterInitializer<ICommand>(commandToInitialize =>
{
commandToInitialize.ExecuteAsynchroniously = true;
});
The given configuration calls the delegate after the creation of each type that implements
ICommand and will set the
ExecuteAsynchroniously property to
true. This is a powerful mechanism that allows attribute free property injection.
Singleton
There will be only one instance of the registered service type during the lifetime of that container instance. Clients will always receive that same instance.
There are multiple ways to register singletons. The most simple and common way to do this is by specifying both the service type and the implementation as generic type arguments. This allows the implementation type to be constructed using automatic constructor injection:
container.Register<IService, RealService>(Lifestyle.Singleton);
// Alternatively, you can use the following short cut
container.RegisterSingle<IService, RealService>();
You can also use the
RegisterSingle<T>(T) overload to assign a constructed instance manually:
var service = new RealService(new SqlRepository());
container.RegisterSingle<IService>(service);
There is also an overload that takes an
Func<T> delegate. The container guarantees that this delegate is called only once:
container.Register<IService>(() => new RealService(new SqlRepository()), Lifestyle.Singleton);
// Or alternatively:
container.RegisterSingle<IService>(() => new RealService(new SqlRepository()));
Alternatively, when needing to register a concrete type as singleton, you can use the parameterless
RegisterSingle<T>() overload. This will inform the container to automatically construct that concrete type (at most) once, and return that instance on each request:
container.RegisterSingle<RealService>();
// Which is a more convenient short cut for:
container.Register<RealService, RealService>(Lifestyle.Singleton);
Note that registration for concrete singletons is necessarily, because unregistered concrete types will be treated as transient.
When you have a type that you want to be created using automatic constructor injection, but need some configuration that can't be done using constructor injection, you can use the
RegisterInitializer method. It takes an
Action<T> delegate:
container.RegisterSingle<IService, RealService>();
container.RegisterInitializer<IService>(serviceToInitialize =>
{
serviceToInitialize.Logger = container.GetInstance<ILogger>();
});
The given configuration calls the delegate after the creation of each type that implements
IService and will inject the
Logger property with the configured
ILogger instance. This is a powerful mechanism that allows attribute free property injection. Note that the
RegisterInitializer only registers an initializer, and it does not say anything about the lifestyle. You still need to call
RegisterSingle to tell the container that the service is a singleton.
Scoped
For every request within a implicitly or explicitly defined scope, a single instance of the service will be returned and that instance will (optionally) be disposed when the scope ends.
Simple Injector contains three scoped lifestyles:
Both
Per Web Request and
Per WCF Operation implement scoping implicitly, which means that the user does not have to start or finish the scope to allow the lifestyle to end and to dispose cached instances. The framework does this for you. With the
Per Lifetime Scope lifestyle on the other hand, you explicitly define a scope (just like you would do with .NET's TransactionScope class).
The default behavior of the
Simple Injector is to
not keep track of instances and to not dispose them. The scoped lifestyles on the other hand are the exceptions to this rule. Although most of your services should be registered either as
Transient or
Singleton, scoped lifestyles are especially useful for implementing patterns such as the
Unit of Work.
Per Web Request
Only one instance will be created by the container per web request and the instance will be disposed when the web request ends (unless specified otherwise).
The
ASP.NET Integration NuGet Package is available (and available as
SimpleInjector.Integration.Web.dll in the default download here on CodePlex) contains
RegisterPerWebRequest extension methods and a
WebRequestLifestyle class that enable easy
Per Web Request registrations:
container.RegisterPerWebRequest<IUserRepository, SqlUserRepository>();
container.RegisterPerWebRequest<IOrderRepository, SqlOrderRepository>();
// The same behavior can be achieved by using the WebRequestLifestyle class.
var webLifestyle = new WebRequestLifestyle();
container.Register<IUserRepository, SqlUserRepository>(webLifestyle);
container.Register<IOrderRepository, SqlOrderRepository>(webLifestyle);
// Alternatively, when cached instance that implement IDisposable, should NOT
// be disposed, you can do the following
var withoutDispose = new WebRequestLifestyle(false);
container.Register<IUserRepository, SqlUserRepository>(withoutDispose);
In contrast to the default behavior of the Simple Injector, these extension methods ensure the created service is disposed (when such an instance implements
IDisposable). This is done at the end of the web request. During startup a HttpModule is automatically registered for you that ensures all created instances are disposed when the web request ends.
Tip: For ASP.NET MVC, there's a Simple Injector MVC Integration Quick Start NuGet Package available that helps you get started with Simple Injector in MVC applications quickly.
Optionally you can register other services for disposal at the end of the web request:
container.Register<IService, ServiceImpl>();
container.RegisterInitializer<ServiceImp>(s =>
SimpleInjectorWebExtensions.RegisterForDisposal(s));
This ensures that each time a
ServiceImp is created by the container, it is registered for disposal when the web request ends.
Note: To be able to dispose an instance, the RegisterForDisposal will store the reference to that instance in the HttpContext Items cache. This means that the instance will be kept alive for the duration of that request.
Note: Be careful not to register services for disposal that outlive the web request itself (such as services registered as singleton), since such service can obviously not be used after it has been disposed.
Per WCF Operation
Only one instance will be created by the container per call to a WCF operation and the instance will be disposed when the operation ends (unless specified otherwise).
The
ASP.NET Integration NuGet Package is available (and available as
SimpleInjector.Integration.Web.dll in the default download here on CodePlex) contains
RegisterPerWcfOperation extension methods and a
WcfOperationLifestyle class that enable easy
Per WCF Operation registrations:
container.RegisterPerWcfOperation<IUserRepository, SqlUserRepository>();
container.RegisterPerWcfOperation<IOrderRepository, SqlOrderRepository>();
// The same behavior can be achieved by using the WcfOperationLifestyle class.
var wcfLifestyle = new WcfOperationLifestyle();
container.Register<IUserRepository, SqlUserRepository>(wcfLifestyle);
container.Register<IOrderRepository, SqlOrderRepository>(wcfLifestyle);
// Alternatively, when cached instance that implement IDisposable, should NOT
// be disposed, you can do the following
var withoutDispose = new WcfOperationLifestyle(false);
container.Register<IUserRepository, SqlUserRepository>(withoutDispose);
In contrast to the default behavior of the Simple Injector, these extension methods ensure the created service is disposed (when such an instance implements
IDisposable). This is done after the call to the WCF operation has finished.
Besides registering services using the
RegisterPerWcfOperation extension methods, each WCF service markup (the .svc file) should include the following attribute:
Factory="SimpleInjector.Integration.Wcf.SimpleInjectorServiceHostFactory, SimpleInjector.Integration.Wcf"
An exception will be thrown by the framework if this attribute is missing.
Tip: There is a Simple Injector WCF Integration Quick Start NuGet Package available that helps you get started with Simple Injector in WCF quickly.
Optionally you can register other services for disposal at the end of the web request:
container.Register<IService, ServiceImpl>();
container.RegisterInitializer<ServiceImp>(instance =>
{
container.GetCurrentWcfOperationScope()
.RegisterForDisposal(instance);
);
This ensures that each time a
ServiceImp is created by the container, it is registered for disposal when the WCF operation ends.
Note: To be able to dispose an instance, the RegisterForDisposal will store the reference to that instance during the lifetime of the WCF operation. This means that the instance will be kept alive for the duration of that operation.
Note: Be careful not to register services for disposal that outlive the WCF operation itself (such as services registered as singleton), since such service can obviously not be used after it has been disposed.
Per Lifetime Scope
Within a certain (explicitly defined) scope, there will be only one instance of a given service type and the instance will be disposed when the scope ends (unless specified otherwise).
Lifetime Scoping is supported as extension package for Simple Injector. It is available as
Lifetime Scoping Extensions NuGet package and is part of the default download on CodePlex as
SimpleInjector.Extensions.LifetimeScoping.dll. The extension package adds multiple
RegisterLifetimeScope extension method overloads and a
LifetimeScopeLifestyle class, which allow to register services with the
Lifetime Scope lifestyle:
container.RegisterLifetimeScope<IUnitOfWork, NorthwindContext>();
// Or alternatively
container.Register<IUnitOfWork, NorthwindContext>(new LifetimeScopeLifestyle());
Within an explicitly defined scope, there will be only one instance of a service that is defined with the
Lifetime Scope lifestyle:
using (container.BeginLifetimeScope())
{
var uow1 = container.GetInstance<IUnitOfWork>();
var uow2 = container.GetInstance<IUnitOfWork>();
Assert.AreEqual(uow1, uow2);
}
Note: A scope is thread-specific. A single scope should not be used on multiple threads. For instance, do not pass on a scope to other threads and do not wrap a ASP.NET HTTP request with a Lifetime Scope, since ASP.NET can finish a web request on another thread. Use Per Web Request scoping for ASP.NET web applications while running inside a web request. Lifetime scoping however, can still be used in web applications on background threads that are created by web requests or when processing commands in a Windows Service (where each commands gets its own scope). For developing multi-threaded applications, take these guidelines into consideration.
Outside the context of a lifetime scope no instances can be created. An exception is thrown when this happens.
Scopes can be nested. Each scope gets its own set of instances:
using (container.BeginLifetimeScope())
{
var outer1 = container.GetInstance<IUnitOfWork>();
var outer2 = container.GetInstance<IUnitOfWork>();
Assert.AreEqual(outer1, outer2);
using (container.BeginLifetimeScope())
{
var inner1 = container.GetInstance<IUnitOfWork>();
var inner2 = container.GetInstance<IUnitOfWork>();
Assert.AreEqual(inner1, inner2);
Assert.AreNotEqual(outer1, inner1);
}
}
In contrast to the default behavior of the Simple Injector, a lifetime scope ensures the created service is disposed (when such an instance implements
IDisposable), unless explicitly disabled. This is done at the end of the scope.
Optionally you can register other services for disposal at the end of the scope:
container.Register<IService, ServiceImpl>();
container.RegisterInitializer<ServiceImp>(intance =>
{
container.GetCurrentLifetimeScope().RegisterForDisposal(instance);
});
This ensures that each time a
ServiceImp is created by the container, it is registered for disposal when the scope (in which it is created) ends.
Note: To be able to dispose an instance, the RegisterForDisposal will store the reference to that instance within the scope. This means that the instance will be kept alive for the duration of that scope.
Note: Be careful not to register services for disposal that outlive the scope itself (such as services registered as singleton), since such service can obviously not be used after it has been disposed.
Per Graph
For each explicit call to
Container.GetInstance<T> a new instance of the service type will be created, but that instance will be reused within the object graph that gets constructed. Compared to
Transient, there will be just a single instance per explicit call to the container, while
Transient services can have multiple new instances per explicit call to the container. This lifestyle can be simulated by using the
Per Lifetime Scope lifestyle.
Per Thread
There will be one instance of the registered service type per thread.
This lifestyle is deliberately left out of the
Simple Injector because
it is considered to be harmful. Instead of using Per Thread lifestyle, you will usually be better of using one of the
Scoped lifestyles.
Hybrid
A hybrid lifestyle is a mix between two or more lifestyles where the the developer defines the context for which the wrapped lifestyles hold.
Simple Injector has no built-in hybrid lifestyles, but has a simple mechanism to define hybrid lifestyles. Example:
var hybridLifestyle = Lifestyle.CreateHybrid(
lifestyleSelector: () => HttpContext.Current != null,
trueLifestyle: new WebRequestLifestyle(),
falseLifestyle: Lifestyle.Transient);
// The created lifestyle can be reused for many registrations.
container.Register<IUserRepository, SqlUserRepository>(hybridLifestyle);
container.Register<ICustomerRepository, SqlCustomerRepository>(hybridLifestyle);
In the previous example an hybrid lifestyle was defined wrapping a
Web Request lifestyle and the
Transient lifestyle. The supplied
lifestyleSelector predicate returns
true when the container should use the
Web Request lifestyle and
false when the
Transient lifestyle should be selected.
A hybrid lifestyle is useful for registrations that must dynamically switch lifestyles throughout the lifetime of the application. The shown hybrid example might be useful in a web application, where some operations run outside the context of an
HttpContext (in a background thread for instance). Please note though that when the lifestyle doesn't have to change throughout the lifetime of the application, a hybrid lifestyle is not needed. A normal lifestyle can be registered instead:
var lifestyle = RunsOnWebServer ? new WebRequestLifestyle() : new LifetimeScopeLifestyle();
// The created lifestyle can be reused for many registrations.
container.Register<IUserRepository, SqlUserRepository>(lifestyle);
container.Register<ICustomerRepository, SqlCustomerRepository>(lifestyle);
Developing a Custom Lifestyle
The lifestyles supplied by the framework should be sufficient for most scenarios, but in rare circumstances a defining a custom lifestyle is useful. This can be done by creating a class that inherits from
Lifestyle and let it return custom
Lifestyle instances. This however is a lot of work, and a shortcut is available in the form of the
Lifestyle.CreateCustom. Please take a look at the example given on the
CreateCustom documentation.
Are you missing examples for other lifestyles? Please let us know!