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

.NET Core自定义服务工厂自动释放问题:实例Dispose未触发求助

问题确认与解决方案

推测正确性确认

你的推测完全正确。.NET的DI容器(ServiceProvider)仅会跟踪由它自身创建的实现IDisposable接口的服务实例。当自定义工厂绕过ServiceProvider直接实例化服务(比如用new MyService(...))时,容器无法感知这些实例的存在,因此在ASP.NET服务器关闭、容器释放时,不会调用这些实例的Dispose方法。

触发Dispose的可行方案

方案1:让工厂通过ServiceProvider创建实例

不要直接new服务,而是通过IServiceProvider或IServiceScopeFactory来创建实例,让容器跟踪这些实例:

public class MyServiceFactory
{
    private readonly IServiceScopeFactory _scopeFactory;

    public MyServiceFactory(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    public MyService CreateService(MyConfig config)
    {
        // 创建独立作用域,用于管理该实例的生命周期
        var scope = _scopeFactory.CreateScope();
        var provider = scope.ServiceProvider;
        
        // 从DI获取依赖,结合自定义配置创建实例
        var dependency = provider.GetRequiredService<IMyDependency>();
        var service = ActivatorUtilities.CreateInstance<MyService>(provider, dependency, config);
        
        // 若需长期持有实例,需保留scope引用,在合适时机手动释放scope以触发Dispose
        return service;
    }
}

注意:如果需要长期持有创建的服务实例,不能用using包裹scope,否则scope释放时实例会被立即销毁。此时需保留scope引用,在服务器关闭或实例不再被使用时手动释放scope,触发实例的Dispose。

方案2:工厂自行跟踪实例并在应用关闭时释放

如果必须绕过ServiceProvider创建实例,可让工厂自行维护实例列表,并在应用关闭时手动调用Dispose:

public class MyServiceFactory : IDisposable
{
    private readonly ConcurrentBag<MyService> _createdServices = new();
    private readonly IHostApplicationLifetime _appLifetime;

    public MyServiceFactory(IHostApplicationLifetime appLifetime)
    {
        _appLifetime = appLifetime;
        // 注册应用关闭事件,触发实例销毁
        _appLifetime.ApplicationStopping.Register(DisposeAllServices);
    }

    public MyService CreateService(MyConfig config)
    {
        var service = new MyService(config);
        _createdServices.Add(service);
        return service;
    }

    private void DisposeAllServices()
    {
        foreach (var service in _createdServices)
        {
            service.Dispose();
        }
    }

    public void Dispose()
    {
        DisposeAllServices();
    }
}

这种方式需注意线程安全,避免实例创建与销毁时的并发冲突。

方案3:用ActivatorUtilities让容器参与实例创建

如果服务部分依赖来自DI、部分是自定义配置,可使用ActivatorUtilities.CreateInstance方法——它会从ServiceProvider解析构造函数依赖,同时允许传入自定义参数,创建的实例会被容器跟踪(需在指定scope内创建):

public MyService CreateService(IServiceProvider provider, MyConfig config)
{
    var service = ActivatorUtilities.CreateInstance<MyService>(provider, config);
    // 若需容器完全管理生命周期,可将实例注册到当前scope的服务集合中
    // provider.GetRequiredService<IServiceCollection>().AddSingleton(service);
    return service;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 15:45:43