You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Autofac如何避免释放通过ServiceCollection注册的服务?

如何避免Autofac释放通过ServiceCollection注册的外部服务?

通过ServiceCollection注册服务可以实现在不同DI容器(如Autofac、Simple Injector、Microsoft.Extensions.DependencyInjection)间切换,但在Autofac中复用ServiceCollection时,外部创建的IDisposable服务会被意外释放——而直接用Autofac注册时,我们可以通过.ExternallyOwned()避免这个问题。

以下是几种可行的解决方案:

方法1:修改ServiceCollection注册的释放权限

在注册外部实例时,通过显式创建ServiceDescriptor并设置AllowDisposal = false,禁止DI容器跟踪并释放该实例。

using Autofac;
using Autofac.Extensions.DependencyInjection;
using DI_Sandbox.Models;
using Microsoft.Extensions.DependencyInjection;

var externalService = new ConsoleMessageWriter();

var services = new ServiceCollection();
// 显式配置服务描述符,禁止容器释放实例
services.Add(new ServiceDescriptor(
    typeof(IMessageWriter),
    externalService,
    ServiceLifetime.Singleton)
{
    AllowDisposal = false
});

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");

预期输出:

Hello DI!
THE END

方法2:在Autofac中覆盖ServiceCollection的注册

跳过Populate中对应的服务注册,直接在Autofac里重新注册目标实例并标记为ExternallyOwned(),强制Autofac不管理该实例的生命周期。

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);
// 覆盖原有注册,标记实例为外部拥有
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");

预期输出与方法1一致。

方法3:批量修改Autofac注册的所有权

如果需要批量处理多个外部实例,可以在Populate后遍历Autofac的注册项,将目标实例的所有权设置为外部拥有。

using Autofac;
using Autofac.Core;
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);

// 遍历注册项,找到目标实例并修改所有权
foreach (var registration in builder.ComponentRegistry.Registrations)
{
    if (registration.Services.Contains(new TypedService(typeof(IMessageWriter))) &&
        registration is ComponentRegistration compReg &&
        compReg.Activator is InstanceActivator activator &&
        activator.Instance == externalService)
    {
        compReg.Ownership = InstanceOwnership.ExternallyOwned;
    }
}

var container = builder.Build();

using(var serviceProvider = new AutofacServiceProvider(container))
{
    var messageWriter = serviceProvider.GetRequiredService<IMessageWriter>();
    messageWriter.Write("Hello DI!");
}

Console.Write("THE END");

原理说明

默认情况下,使用ServiceCollection.AddSingleton(instance)注册时,AllowDisposal属性为true,Microsoft DI会跟踪该实例的生命周期;Autofac在执行Populate时会继承这一行为,因此容器释放时会调用实例的Dispose方法。

通过设置AllowDisposal = false或在Autofac中标记ExternallyOwned(),可以明确告知容器:该实例由外部代码负责管理,容器无需处理其释放逻辑。

内容的提问来源于stack exchange,提问作者Andrey Bushman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:52:22