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.
Related
I have a class "DependencyResolver" where I return instances of objects by hand. There I used "Activator.CreateInstance".
I wanted to change it so it uses autofac.
My function "Get" works fine:
public T Get<T>()
{
return _container.Resolve<T>();
}
But I also have a function "CreateNew" where I need a new instance:
public T CreateNew<T>()
{
return _container.Resolve<T>();
}
The Problem is that I always get the same instance.
My Registration looks like this:
var builder = new ContainerBuilder();
foreach (var dllFileName in DependencyMapping.GetAllDllFilenames())
{
builder
.RegisterAssemblyTypes(Assembly.LoadFile(Path.Combine(GetPathFromInstalledSys(), dllFileName)))
.AsImplementedInterfaces()
.SingleInstance();
}
_container = builder.Build();
So there is a place where I can control the behaviour: "SingleInstance" or "InstancePerDependency". But I dont know whether the user needs a new instance or not. Is there any way to change the behavior when "CreateNew" is called?
Lifetime scope (single instance, instance per dependency) is controlled at registration time, not resolve time. There's no way to change it. This is the case with all DI containers, not just Autofac. Part of the point of it is that the consumer shouldn't have to know what scope they want - they just ask for a thing and get it.
Consumers also generally shouldn't deal with disposal - things get disposed by the container.
Note what you have here is service location (client asks the container for a thing), not dependency injection (client takes dependencies in constructor and doesn't know about the container). While service location is sometimes required, generally try to avoid it if you can; it's not really much better than just calling new in your code.
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).
Is it bad If I use the ServiceProvider interface to resolve my properties in .NET Core for Dependency Injection
let say I have the following
private readonly IRecipeRepository _recipeRepository;
private readonly IMediaResource _resourceUpload;
private readonly IAWSMedia _awsMedia;
and then do this
public RecipeService(IServiceProvider service)
{
_recipeRepository = service.GetService<IRecipeRepository>();
_resourceUpload = service.GetService<IMediaResource>();
_awsMedia = service.GetService<IAWSMedia>();
}
instead of this
public RecipeService(IRecipeRepository recipeRepo, IMediaResource media, IAWSMedia awsMedia )
{
_recipeRepository = recipeRepo;
_resourceUpload = media;
_awsMedia = awsMedia ;
}
The first bit of code is called the service locator anti-pattern, as in something you should not do. However, the answer to your question depends on context you have not provided.
In the majority of cases, no, you should not just inject IServiceProvider. However, in some scenarios, you have no choice but to: namely with things in singleton scope. If you have a singleton-type class, an IHostedService implementation, etc., you cannot inject anything but other singleton-scoped services. If you need something in a different scope like a DbContext, then you can only get that by injecting IServiceProvider and creating a scope:
using (var scope = _serviceProvider.CreateScope())
{
var foo = scope.ServiceProvider.GetRequiredService<Foo>();
// do something with foo;
}
However, remember that the instance retrieved is tied to the scope. In other words, when the using statement closes, it will be disposed. Therefore, you need to do any work with that instance inside that scope. You cannot do something like set an instance variable on your class, and the attempt to use it later, as you'll then get an ObjectDisposedException.
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 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.