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?