If I will register all services through ServiceCollection
then I get capability for switching between different DI implementations that reused this collection: Autofac
, Simple Injector
, or Microsoft.Extensions.DependencyInjection
.
But when I try to reuse the ServiceCollection
through Autofac
it disposes the external service. This is a problem...
Some external service:
namespace DI_Sandbox.Models
{
public interface IMessageWriter
{
void Write(string message);
}
public class ConsoleMessageWriter: IMessageWriter, IDisposable
{
public void Dispose()
{
Console.WriteLine($"The {GetType().Name} instanse is disposed.");
}
public void Write(string message)
{
Console.WriteLine(message);
}
}
}
It is possible to prevent disposing service, registered in Autofac directly (i.e. without using ServiceCollection
):
using Autofac;
using Autofac.Extensions.DependencyInjection;
using DI_Sandbox.Models;
using Microsoft.Extensions.DependencyInjection;
var externalService = new ConsoleMessageWriter();
var builder = new ContainerBuilder();
builder.RegisterInstance<IMessageWriter>(externalService).ExternallyOwned();
var container = builder.Build();
using(var serviceProvider = new AutofacServiceProvider(container))
{
var messageWriter = serviceProvider.GetRequiredService<IMessageWriter>();
messageWriter.Write("Hello DI!");
}
Console.Write("THE END");
The output is expected:
Hello DI!
THE END
My attempting to reuse in Autofac
the services are registered through ServiceCollection
:
using Autofac;
using Autofac.Extensions.DependencyInjection;
using DI_Sandbox.Models;
using Microsoft.Extensions.DependencyInjection;
var externalService = new ConsoleMessageWriter();
var services = new ServiceCollection();
services.AddSingleton<IMessageWriter>(externalService);
var builder = new ContainerBuilder();
builder.Populate(services);
var container = builder.Build();
using(var serviceProvider = new AutofacServiceProvider(container))
{
var messageWriter = serviceProvider.GetRequiredService<IMessageWriter>();
messageWriter.Write("Hello DI!");
}
Console.Write("THE END");
The result:
Hello DI!
The ConsoleMessageWriter instanse is disposed.
THE END
How to prevent disposing service is registered through ServiceCollection
and reused by Autofac
?
The problem you are running into is described in this issue:
Apparently, the autofac adapter doesn't try to differentiate between singleton registrations when loading the service registrations from the IServiceCollection
, and will end up not applying the ExternallyOwned
flag or whatever to them.
The author suggests the following workaround: register directly to Autofac: https://github.com/autofac/Autofac.Extensions.DependencyInjection/issues/15#issuecomment-314425353
The workaround now is to register directly with Autofac instead of the adapter.
Personally, I think this workaround is terrible and that the Autofac implementation is just buggy, but they went ahead and closed the issue. Apparently, from their perspective, it's working by design.
I know this is a bit off topic, but I'd just honestly suggest dropping Autofac here and sticking with Microsoft.Extensions.DependencyInjection
if you can.
UPDATE April 29th 2024: