I'm investigating a memory leak in my application. Here's the context:
Let's assume I have to process different types of XMLs files and I receive a large amount of XML files per day, so I have a IXmlProcessor interface .
public interface IXmlProcessor
{
void ProcessXml(string xml);
}
And some concrete XMLProcessors.
public class UserXmlProcessor : IXmlProcessor
{
private readonly IUserRepository _userRepository;
public UserXmlProcessor(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void ProcessXml(string xml)
{
// do something with the xml
// call _userRepository
}
}
All IXmlProcessor concrete types are registered to the DI Container, and to resolve them I have a Factory class, that's also registered to the DI container, something like this:
public class XmlProcessorFactory where TType : class
{
private readonly IServiceProvider _serviceProvider;
public XmlProcessorFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IXmlProcessor GetImplementation(string identifier)
{
var type = FindType(identifier);
return _serviceProvider.GetService(type) as IXmlProcessor;
}
private Type FindType(string identifier)
{
// do some reflection to find the type based on the identifier (UserXmlProcessor, for example)
// don't worry, there's caching to avoid unecessary reflection
}
}
And at some point I call them all:
public class WorkItem
{
public string Identifier { get; set; }
public string Xml { get; set; }
}
public class WorkingClass
{
private readonly XmlProcessorFactory _xmlProcessorFactory;
public WorkingClass(XmlProcessorFactory xmlProcessorFactory)
{
_xmlProcessorFactory = xmlProcessorFactory;
}
public void DoWork(WorkItem item)
{
var processor = _xmlProcessorFactory.GetImplementation(item.Identifier);
processor.ProcessXml(item.Xml);
}
}
IUserRepository is a straightforward implementation, with an Entity Framwork context.
So, here's the problem: according to the Microsoft documentation:
Services resolved from the container should never be disposed by the developer.
Receiving an IDisposable dependency via DI doesn't require that the receiver implement IDisposable itself. The receiver of the IDisposable dependency shouldn't call Dispose on that dependency.
So if I inject IUserRepository to a controller, that's fine, the container will handle the object's disposal as well as the EF Context's disposal, none needs to be IDisposable.
But what about my Xml Processors? The documentation says:
Services not created by the service container
The developer is responsible for disposing the services.
Avoid using the service locator pattern. For example, don't invoke GetService to obtain a service instance when you can use DI instead.
Another service locator variation to avoid is injecting a factory that resolves dependencies at runtime. Both of these practices mix Inversion of Control strategies.
And also _ = serviceProvider.GetRequiredService<ExampleDisposable>(); being an anti-pattern. But as you can see I do need to resolve the dependency at runtime, based on the XML Identifier and I dont' want to resort to switch cases.
So:
Should the IXmlProcessors implement IDisposable and release IUserRepository manually?
Should I also cascade and make IUserRepository implement IDisposable to release EntityContext?
If so, wouldn't that affect the service lifetime if it's injected in a controller?
And also _ = serviceProvider.GetRequiredService<ExampleDisposable>(); being an anti-pattern.
This statement is too simplistic. Calling GetRequiredService is not an implementation of the Service Locator anti-pattern when called from within the Composition Root, and is, therefore, fine. When called outside the Composition Root, it is an implementation of the Service Locator anti-pattern. Most downsides that calling
GetRequiredService has only exist when used outside the Composition Root.
Should the IXmlProcessors implement IDisposable and release IUserRepository manually?
No. The Microsoft Documentation is right. When your IUserRepository is resolved from the container, the Container will ensure it (or its dependencies) gets disposed of. Adding dispose logic in IUserRepository's consumers to dispose the repository only leads to unneeded complexity in the consumer. The dependency would only get disposed twice.
Should I also cascade and make IUserRepository implement IDisposable to release EntityContext?
No. When the EntityContext is managed by the DI Container, again, it will ensure it gets disposed of. So IUserRepository implementations should not implement disposal just to ensure that EntityContext gets disposed of. The Container will do this.
If so, wouldn't that affect the service lifetime if it's injected in a controller?
One of the problems with implementing IDisposable on the consumer is that this ripples through the system. Making a low-level dependency disposable, will force you to make all consumers in the dependency chain disposable as well. Not only does this lead to (unneeded) complexity in the consumers, it forces many classes in the system to be updated. This also means tests required to be added for all these classes. This would be a typical example of an Open/Closed Principle violation.
Do note that with the default .NET Core DI Container, it is very easy to accidentally cause memory leaks. This will happen when you resolve disposable Scoped or Transient components directly from the root container, instead of resolving them from a IServiceScope. Especially disposable Transient components are nasty, because at first it seems to work (as you always get a new instance), but those disposable Transients will be kept alive until the Container itself is disposed of, which will typically only happen on application shutdown.
So make sure you always resolve from a service scope, never from the root container (except when you run a short-lived (console) application).
Related
I recently came across AddPooledDbContextFactory concept as part of my NET 5 self-education piece and am keen to implement it properly. However, I am not sure how to use it with generics that I generally use.
Example of my current setup:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TestDbContext>(
(s, o) => o.UseNpgsql(Configuration.GetConnectionString("DatabaseConnection"))
.UseLoggerFactory(s.GetRequiredService<ILoggerFactory>()));
// other code //
}
my repository generic:
public class Repository<T> : IRepository<T> where T
{
private readonly TestDbContext _dbContext;
public Repository(TestDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Create(T entity)
{
await _dbContext.Set<T>().AddAsync(entity);
await _dbContext.SaveChangesAsync();
}
// other methods //
}
this is invoked in following manner as example:
public class WeatherForecastController : ControllerBase
{
private readonly IRepository<Test> testRepo;
public WeatherForecastController(IRepository<Test> testRepo)
{
this.testRepo= testRepo;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> GetAsync()
{
await testRepo.Create(new Test { Name = "Superman" });
// other code
}
}
I would like to convert this to use the new AddPooledDbContextFactory concept but cannot find enough documentation to figure out how to do this.
Atm only thing that comes to mind is using statements at each method but that doesn't make sense.
Any advice on this?
Documentation is not yet complete and is in progress, you track this issue
https://github.com/dotnet/EntityFramework.Docs/issues/2523
You can also a look at the tests for AddPooledDbContextFactory to see how to register DbContext with
https://github.com/dotnet/efcore/search?q=AddPooledDbContextFactory
for example to register DbContext:
services.AddPooledDbContextFactory<TContext>(ob =>
ob.UseSqlServer("ConnectionString").EnableServiceProviderCaching(false), poolSize: 32)
Then in your class, inject an IDbContextFactory<TContext> and use it like this:
using(var context = _factory.CreateDbContext())
{
var orders = await context.Orders.Where(o => o.Id > 3).ToListAsync();
}
According to this post:
Note that the DbContext instances created in this way are not managed
by the application's service provider and therefore must be disposed
by the application
You can also check out this post to see how to use IDbContextFactory:
https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-5.0
#Aeseir your code looks good to me. You are following best practices and you don't need to change it.
You are using the Repository Pattern, so your Repository class has all of your query logic which helps create loosely coupled and maintainable code.
In your ConfigureServices, calling: services.AddDbContext<TestDbContext>() registers TestDbContext with Scoped service lifetime. This is the way that DbContext is designed to work, and it will also work well with ASP.NET controllers, since they have a Scoped lifetime as well.
You did not show your code for registering IRepository, but that service lifetime should be Scoped as well. Btw, you can tell BuildServiceProvider() to validate scope registrations:
builder.Services.BuildServiceProvider(validateScopes: true);
Since DbContext is designed to have a Scoped service lifetime, and since your IRepository and Controller services are Scoped as well, every request gets brand new:
Controller
IRepository
DbContext
Those services are used for the request and then Diposed. This is how ASP.NET is intended to work.
Apparently at some point, DbContext pooling has been introduced to improve performance. In this case, EF Core manages a pool of context instances for you and resets them after each request. This can improve performance, although in some situations, the benefit might be small. See MSDN documentation for more details.
I think for use with ASP.NET controllers (i.e. the code you posted above) all you need to do to take advantage of EF Core context pooling is call AddDbContextPool():
builder.Services.AddDbContextPool<ApplicationDbContext>(/* ... */);
However, if you needed to use DbContext in services registered with Singleton lifetime, then the pattern above would not work well. Because when a Scoped service gets used in a Singleton service, the Scoped service is essentially a Singleton. Each request would not get a new DbContext, nor a reset one from the pool. (See QUESTION below.)
In that case, you might want to use the DbContext factory pattern instead:
builder.Services.AddDbContextFactory<ApplicationDbContext>(/* ... */);
Or, if you want to use context pooling with a factory pattern:
builder.Services.AddPooledDbContextFactory<ApplicationDbContext>(/* ... */);
The DbContextFactory can then be used in other services through constructor injection. For example:
private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
public MyController(IDbContextFactory<ApplicationDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
The injected factory can then be used to construct DbContext instances in the controller code. For example:
public void DoSomething()
{
using (var context = _contextFactory.CreateDbContext())
{
// ...
}
}
Keep in mind that when you call CreateDbContext(), context instances are not managed by the service provider and therefore must be disposed by the application. Hence you need to Dispose of them yourself, such as in the example above which does so with the using statement.
QUESTION
I am doing my best to understand this stuff and explain it, but I might be wrong, so please call out an inaccuracies in my post.
When using AddDbContextPool(), does the DbContext get registered as a Singleton or Scoped?
I found in MSDN documentation that it's effectively registered as a Singleton:
Context pooling works by reusing the same context instance across requests; this means that it's effectively registered as a Singleton, and the same instance is reused across multiple requests (or DI scopes). This means that special care must be taken when the context involves any state that may change between requests.
However, I have found that if AddDbContextPool() is used along with true for validatedScopes:
builder.Services.BuildServiceProvider(validateScopes: true)
When DbContext is consumed from another service which is registered as a Singleton, the following exception is thrown:
System.InvalidOperationException: 'Cannot consume scoped service 'ApplicationDbContext' from singleton 'IRepository'.'
Hence why I stated above that DbContext still gets Scoped service lifetime.
I have a factory class in a Net Core 3 console app which needs to be able to resolve against a DI container at runtime:
public class OptionFactory : IOptionFactory
{
private readonly IServiceProvider _svcProvider;
public OptionFactory( IServiceProvider svcProvider )
{
_svcProvider = svcProvider;
}
public IOption<T>? CreateOption<T>( params string[] keys )
{
// code eliminated for brevity
try
{
return retVal = _svcProvider.GetRequiredService<Option<T>>();
}
catch( Exception e )
{
return null;
}
}
}
I'm using Autofac to define the DI container and then "assign" it to IServiceProvider via new AutofacServiceProvider( builder.Build() ) in a provider class:
public class TestServiceProvider
{
public static IServiceProvider Instance { get; private set; }
static TestServiceProvider()
{
var builder = new ContainerBuilder();
builder.RegisterType<OptionFactory>()
.As<IOptionFactory>()
.SingleInstance();
// code omitted for brevity
Instance = new AutofacServiceProvider( builder.Build() );
}
}
I'm unclear about how to register IServiceProvider itself with the DI container so that it can be injected into the constructor. Is that even possible? It seems a little self-referential, which could be problematic.
All the examples I've seen online call for referencing back to the Autofac IContainer itself, (or to TestServiceProvider.Instance in my example). I can do that, but it would end tie my library to a concrete service provider class. Which I think I'd like to avoid if I can.
I realize injecting IServiceProvider is considered an anti-pattern by some/many, although others deem it acceptable in a factory class because the factory is "simply" extending the DI container. I'm open to other approaches which don't rely on a factory class, provided they allow me to create concrete instances of open generic types at runtime.
You have a couple of options (no pun intended 😃).
Easiest: Call builder.Populate() with an empty collection
The Autofac.Extensions.DependencyInjection package (which you're using, since you have AutofacServiceProvider) has an extension method ContainerBuilder.Populate() which handles registering stuff from an IServiceCollection and auto-registering the AutofacServiceProvider. You could call that method with an empty service collection and it'll work.
builder.Populate(Enumerable.Empty<ServiceDescriptor>());
This will get you exactly the thing you're looking for. However, there's an alternative to consider...
Alternative: Use ILifetimeScope
If it doesn't matter whether your OptionFactory is tied to Autofac, you can inject ILifetimeScope. Autofac has the current lifetime scope auto-registered, so this will work:
public OptionFactory(ILifetimeScope scope)
{
// scope is whatever lifetime scope the
// factory itself came from - if that's the
// root container, then the scope is the
// container
}
The benefit here is you'll get the richer resolve options Autofac offers without any extra work. The drawback would be you're tied to Autofac at this level, which may or may not matter.
Beware!
It may just be your example, but there's something important to know if you're resolving directly from the root container the way the example shows:
You could easily end up with a big memory leak.
Autofac holds on to all IDisposable instances it resolves so they can be safely disposed when the lifetime scope is disposed. If you are resolving from the container, that means any IDisposable will be held onto until the container itself is disposed, which, for most, is the lifetime of the application. That means - hypothetically - every resolution could be adding just a tiny little bit of memory that won't be disposed until the container is disposed. Memory leak.
For this reason we recommend always resolving from a nested lifetime scope rather than from the container. In a web app, that request-level lifetime scope is perfect because it disappears after a request. In an example like this, it's up to you and your app code to determine the best way to integrate lifetime scopes.
And, of course, if you're definitely, 100% guaranteed never resolving anything IDisposable, no worries.
I'm trying to get something like this working:
public class FooService : IFooService {
public FooService(Func<IBarService> barFactory) { ... }
}
public class BarService : IBarService, IDisposable { ... }
services.AddSingleton<IFooService, FooService>();
services.AddTransient<IBarService, BarService>();
services.AddSingleton<Func<IBarService>>(ctx => () => ctx.GetService<IBarService());
This works as far as resolving the BarService instance, but I can't figure out how to properly manage its lifetime. When I do this inside one of the members of FooService:
using (var bar = _barFactory())
{
...
}
I get an ObjectDispoedException:
System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
However, if I just do var bar = _barFactory();, without the using statement, I have no way to signal to the DI container that I'm done with the instance, and it can be disposed.
What's the correct approach here?
(Side note: yes, I know that some will object that a singleton service should not be dependent on a transient service. That's not what's happening here; the singleton service is dependent on a singleton factory, that produces transient instances. The singleton then uses the transient service for one or two statements and then is done with it, so there should be no actual lifetime problems here.)
As described in documentation:
The container will call Dispose for IDisposable types it creates. However, if you add an instance to the container yourself, it will not be disposed.
So just don't use using statement and all should be OK.
I am using ASP.NET MVC WebApi 2 and injecting concrete types into controllers using Unity 3 and this Unity MVC bootstrapper.
The issue here is that one the registered types initialises an Entity Framework 6 DbContext for every resolve:
public sealed class EntityFrameworkUnitOfWork : IUnitOfWork
{
internal DbContext Context { get; private set; }
public EntityFrameworkUnitOfWork()
{
Context = new SomeContext();
}
public void Commit()
{
Context.SaveChanges();
}
public void Dispose(bool disposing)
{
if (disposing)
{
if (Context != null)
{
Context.Dispose();
Context = null;
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
For example, the EntityFrameworkUnitOfWork would be constructor injected into a controller like this:
public class UserController : ApiController
{
public UsersController(IUserRepository userRepository, IUnitOfWork unitOfWork)
{
// unitOfWork is a EntityFrameworkUnitOfWork
}
// ...
}
When the relevant MVC controller disposes, I need the Dispose() method to be called on the above EntityFrameworkUnitOfWork type, which in turn will dispose of the underlying DbContext.
Registering this type with Unity:
Container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>(
new DisposingTransientLifetimeManager()
);
I am using the DisposingTransientLifetimeManager lifetime manager, as suggested in this article, thinking that it would automatically dispose of my IDisposable types. It seems that I still need to call on Container.Teardown(someInstance). This is not possible for me to do as the MVC Bootstrapper is handling all DI resolving.
Where and how can I perform the teardown of these initialised types?
It would be ideal to perform this teardown when the relevant MVC controller destructs, but perhaps this can also occur at the end of the HTTP request?
EDIT:
The IDisposables that are injected aren't necessarily accessible from the controller. For example, I could also inject a IUserService into a controller which itself (the IUserService class) is injected with an IUserRepository and an IUnitOfWork. I could chain Dispose methods from the IUserService to dispose of them, but this would requires changes to hundreds of controllers and services. Ideally I should be able to call container.Dispose() somewhere to have Unity dispose all injected disposables.
EDIT 2:
RaraituL brought something else to mind. IUnitOfwork does not implement IDisposable, only EntityFrameworkUnitOfWork does. This essentially means that the an MVC controller wouldn't be able to call on a dispose method as it only knows of IUnitOfWork. This is another reason why Unity should do this - it created the IDisposables so it should dispose of them too.
Sounds like you want a PerRequestTransientLifetimeManager. That will be something you will have to build. It's not hard and since you are using Unity 3 most of the work is already done for you.
public class PerRequestTransientLifetimeManager : ILifetimePolicy
{
public object GetValue()
{
// will always create a new object (Transient)
return null;
}
public void SetValue(object newValue)
{
// No point in saving to http context if not disposable
if (newValue is IDisposable)
{
var perRequestLifetimeManager = new PerRequestLifetimeManager();
perRequestLifetimeManager.SetValue(newValue);
}
}
public void RemoveValue()
{
// can't remove since transient didn't keep a reference
}
}
You'll need Unity.Mvc nuget package if the PerRequestLifetimeManager class is missing. You'll also need to register the UnityPerRequestHttpModule using Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule
I should point out from MS site
Although the PerRequestLifetimeManager lifetime manager works
correctly and can help in working with stateful or thread-unsafe
dependencies within the scope of an HTTP request, it is generally not
a good idea to use it when it can be avoided, as it can often lead to
bad practices or hard to find bugs in the end-user's application code
when used incorrectly. It is recommended that the dependencies you
register are stateless and if there is a need to share common state
between several objects during the lifetime of an HTTP request, then
you can have a stateless service that explicitly stores and retrieves
this state using the Items collection of the Current object.
You could use the UnityHierarchicalDependencyResolver in the same NuGet package you already reference (Unity.AspNet.WebApi). Then register your services you want disposed with the HierarchicalLifetimeManager. This dependency resolver creates and disposes a new child container on every Web Api request. When a Unity container is disposed, all built up objects in that container are also disposed.
IUnityContainer rootContainer = new UnityContainer();
GlobalConfiguration.Configuration.DependencyResolver =
new UnityHierarchicalDependencyResolver(rootContainer);
rootContainer.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>
(new HierarchicalLifetimeManager());
I have multiple services, each of which have a UnitOfWork injected into the constructor using the Simple Injector IoC container.
Currently I can see each UnitOfWork instance is a separate object, this is bad as i am using Entity Framework and require the same context reference across all units of work.
How can I ensure the same UnitOfWork instance is injected into all services per each resolve request? My UnitOfWor will be saved by an external command handler decorator after the command completes.
Please note, this is a common library and will be used for both MVC and Windows Forms, it would be nice to have a generic solution for both platforms if possible.
Code is below:
// snippet of code that registers types
void RegisterTypes()
{
// register general unit of work class for use by majority of service layers
container.Register<IUnitOfWork, UnitOfWork>();
// provide a factory for singleton classes to create their own units of work
// at will
container.RegisterSingle<IUnitOfWorkFactory, UnitOfWorkFactory>();
// register logger
container.RegisterSingle<ILogger, NLogForUnitOfWork>();
// register all generic command handlers
container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>),
AppDomain.CurrentDomain.GetAssemblies());
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(TransactionCommandHandlerDecorator<>));
// register services that will be used by command handlers
container.Register<ISynchronisationService, SynchronisationService>();
container.Register<IPluginManagerService, PluginManagerService>();
}
The desired outcome of the below line is to create a object which has a shared UnitOfWork instance throughout the constructed object graph:
var handler = Resolve<ICommandHandler<SyncExternalDataCommand>>();
Here are my services:
public class PluginManagerService : IPluginSettingsService
{
public PluginManagerService(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
private readonly unitOfWork;
void IPluginSettingsService.RegisterPlugins()
{
// manipulate the unit of work
}
}
public class SynchronisationService : ISynchronisationService
{
public PluginManagerService(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
private readonly unitOfWork;
void ISynchronisationService.SyncData()
{
// manipulate the unit of work
}
}
public class SyncExternalDataCommandHandler
: ICommandHandler<SyncExternalDataCommand>
{
ILogger logger;
ISynchronisationService synchronisationService;
IPluginManagerService pluginManagerService;
public SyncExternalDataCommandHandler(
ISynchronisationService synchronisationService,
IPluginManagerService pluginManagerService,
ILogger logger)
{
this.synchronisationService = synchronisationService;
this.pluginManagerService = pluginManagerService;
this.logger = logger;
}
public void Handle(SyncExternalDataCommand command)
{
// here i will call both services functions, however as of now each
// has a different UnitOfWork reference internally, we need them to
// be common.
this.synchronisationService.SyncData();
this.pluginManagerService.RegisterPlugins();
}
}
Which registration you need depends on the type of application. Since you are talking about two different frameworks (MVC and WinForms), both will have a different registration.
For an MVC application (or web applications in general), the most common thing to do is to register the unit of work on a per web request basis. For instance, the following registration will cache the unit of work during a single web request:
container.Register<IUnitOfWork>(() =>
{
var items = HttpContext.Current.Items;
var uow = (IUnitOfWork)items["UnitOfWork"];
if (uow == null)
{
items["UnitOfWork"] = uow = container.GetInstance<UnitOfWork>();
}
return uow;
});
The downside of this registration is that the unit of work is not disposed (if needed). There is an extension package for the Simple Injector that adds RegisterPerWebRequest extension methods to the container, which will automatically ensure that the instance is disposed at the end of the web request. Using this package, you will be able to do the following registration:
container.RegisterPerWebRequest<IUnitOfWork, UnitOfWork>();
Which is a shortcut to:
container.Register<IUnitOfWork, UnitOfWork>(new WebRequestLifestyle());
A Windows Forms application on the other hand, is typically single threaded (a single user will be using that application). I believe it is not unusual to have a single unit of work per form, which is disposed the form closes, but with the use of the command/handler pattern, I think it is better to take a more service oriented approach. What I mean by this is that it would be good to design it in such way that you can move the business layer to a WCF service, without the need to make changes to the presentation layer. You can achieve this by letting your commands only contain primitives and (other) DTOs. So don't store Entity Framework entities into your commands, because this will make serializing the command much harder, and it will lead to surprises later on.
When you do this, it would be convenient to create a new unit of work before the command handler starts executing, reuse that same unit of work during the execution of that handler, and commit it when the handler completed successfully (and always dispose it). This is a typical scenario for the Per Lifetime Scope lifestyle. There is an extension package that adds RegisterLifetimeScope extension methods to the container. Using this package, you will be able to do the following registration:
container.RegisterLifetimeScope<IUnitOfWork, UnitOfWork>();
Which is a shortcut to:
container.Register<IUnitOfWork, UnitOfWork>(new LifetimeScopeLifestyle());
The registration however, is just half of the story. The second part is to decide when to save the changes of the unit of work, and in the case of the use of the Lifetime Scope lifestyle, where to start and end such a scope. Since you should explicitly start a lifetime scope before the command executes, and end it when the command finished executing, the best way to do this, is by using a command handler decorator, that can wrap your command handlers. Therefore, for the Forms Application, you would typically register an extra command handler decorator that manages the lifetime scope. This approach does not work in this case. Take a look at the following decorator, but please note that it is incorrect:
private class LifetimeScopeCommandHandlerDecorator<T>
: ICommandHandler<T>
{
private readonly Container container;
private readonly ICommandHandler<T> decoratedHandler;
public LifetimeScopeCommandHandlerDecorator(...) { ... }
public void Handle(T command)
{
using (this.container.BeginLifetimeScope())
{
// WRONG!!!
this.decoratedHandler.Handle(command);
}
}
}
This approach does not work, because the decorated command handler is created before the lifetime scope is started.
We might be tempted into trying to solve this problem as follows, but that isn't correct either:
using (this.container.BeginLifetimeScope())
{
// EVEN MORE WRONG!!!
var handler = this.container.GetInstance<ICommandHandler<T>>();
handler.Handle(command);
}
Although requesting an ICommandHandler<T> inside the context of a lifetime scope, does indeed inject an IUnitOfWork for that scope, the container will return a handler that is (again) decorated with a LifetimeScopeCommandHandlerDecorator<T>. Calling handler.Handle(command) will therefore result in a recursive call and we'll end up with a stack overflow exception.
The problem is that the dependency graph is already built before we can start the lifetime scope. We therefore have to break the dependency graph by deferring building the rest of the graph. The best way to do this that allows you to keep your application design clean] is by changing the decorator into a proxy and injecting a factory into it that will create the type that it was supposed to wrap. Such LifetimeScopeCommandHandlerProxy<T> will look like this:
// This class will be part of the Composition Root of
// the Windows Forms application
private class LifetimeScopeCommandHandlerProxy<T> : ICommandHandler<T>
{
// Since this type is part of the composition root,
// we are allowed to inject the container into it.
private Container container;
private Func<ICommandHandler<T>> factory;
public LifetimeScopeCommandHandlerProxy(Container container,
Func<ICommandHandler<T>> factory)
{
this.factory = factory;
this.container = container;
}
public void Handle(T command)
{
using (this.container.BeginLifetimeScope())
{
var handler = this.factory();
handler.Handle(command);
}
}
}
By injecting a delegate, we can delay the time the instance is created and by doing this we delay the construction of (the rest of) the dependency graph. The trick now is to register this proxy class in such way that it will inject the wrapped instances, instead of (of course) injecting itself again. Simple Injector supports injecting Func<T> factories into decorators, so you can simply use the RegisterDecorator and in this case even the RegisterSingleDecorator extension method.
Note that the order in which decorators (and this proxy) are registered (obviously) matters. Since this proxy starts a new lifetime scope, it should wrap the decorator that commits the unit of work. In other words, a more complete registration would look like this:
container.RegisterLifetimeScope<IUnitOfWork, UnitOfWork>();
container.RegisterManyForOpenGeneric(
typeof(ICommandHandler<>),
AppDomain.CurrentDomain.GetAssemblies());
// Register a decorator that handles saving the unit of
// work after a handler has executed successfully.
// This decorator will wrap all command handlers.
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(TransactionCommandHandlerDecorator<>));
// Register the proxy that starts a lifetime scope.
// This proxy will wrap the transaction decorators.
container.RegisterSingleDecorator(
typeof(ICommandHandler<>),
typeof(LifetimeScopeCommandHandlerProxy<>));
Registering the proxy and decorator the other way around would mean that the TransactionCommandHandlerDecorator<T> would depend on a different IUnitOfWork than the rest of the dependency graph does, which would mean that all changes made to the unit of work in that graph will not get committed. In other words, your application will stop working. So always review this registration carefully.
Good luck.