繁体   English   中英

.NET Core DI - 在控制台应用程序中处理 Singleton 服务

[英].NET Core DI - disposing of Singleton service in Console App

我有这个小型控制台应用程序,我决定为它连接 Microsoft 的 DI,这样它就会为我处理依赖关系。 我没有那么多范围,而是瞬态和 singleton 服务。

问题是,它不处理 singleton 服务。 也许是因为它不知道我什么时候完成? 也许是因为其他一些原因。

这是我的 static class 处理注入的代码(显然在最终应用程序中它有点复杂)

public static class ServiceInjector
{
    static IServiceProvider _services;

    static Stack<IServiceScope> _scopeStack;

    static IServiceProvider _provider => _scopeStack.NullPeek()?.ServiceProvider ?? _services;

    public static void Configure()
    {
        var svcCollection = new ServiceCollection();
        svcCollection.AddSingleton<ISampleSingletonService, SampleSingletonService>();

        _services = svcCollection.BuildServiceProvider();
        _scopeStack = new Stack<IServiceScope>();
    }

    public static T GetService<T>()
    {
        return _provider.GetService<T>();
    }

    public static void StartScope()
    {
        _scopeStack.Push(_services.CreateScope());
    }

    public static void KillAllScopes()
    {
        while(_scopeStack.TryPop(out IServiceScope scope))
        {
            scope.Dispose();
        }

        _services = null; // I also tried to convince GC to clean it up and force Dispose. Nope.
    }
}

Program.Main我调用ServiceInjector.Configure()方法,然后是ServiceInjector.StartScope() ,然后做一些事情(注入服务),最后(在全局异常处理程序的finally块中)我调用ServiceInjector.KillAllScopes() ,当我想让这一切都弄清楚。 显然这还不够,因为我的SampleSingletonServiceDispose()从未被调用( ISampleSingletonService继承自IDisposable )。

这是一个问题,因为我使用 ILoggerProvider(来自另一个Microsoft.Extensions.包)缓存内容并每隔几秒钟将其刷新到文件中。 如果全局异常处理程序发现一些异常,我会记录它并希望将其刷新到磁盘,然后退出应用程序。 在没有调用Dispose的情况下,应用程序会在刷新最后一条消息之前关闭,因此我会丢失该消息。

显然,我可以将应用程序暂停的时间比刷新所需的时间更长,以确保它完成,但我们只能说这不是完美的解决方案。

我尝试以某种方式处理/清理/关闭根IServiceProvider ,但它没有从IDisposable继承,而且我似乎没有一个可用的方法正在清理它造成的混乱。

我还尝试将_service设置为 null 并调用GC.Collect() ,但垃圾收集器似乎没有兴趣帮助我;)

出于演示目的,我创建了简约的复制应用程序,它显示了问题(来自示例服务的Dispose方法的消息从未被记录): https://github.com/domints/DotnetDISingletonDisposingPoC

感谢您提供有关如何解决该问题的任何想法。

您需要在 _services 字段上调用 Dispose。 处置 scope 时,只会处置作用域服务,而不会处置单例。

var serviceCollection = new ServiceCollection();
// configure services
using var serviceProvider = serviceCollection.BuildServiceProvider();
using var serviceScope = serviceProvider.CreateScope();

我找到了解决方案,也找到了罪魁祸首。 在重新研究这个问题之后,我注意到svcCollection.BuildServiceProvider()的文档和代码不返回IServiceProvider ,而是返回ServiceProvider ,它同时实现了IServiceProviderIDisposable

所以将我的领域更改为:

static ServiceProvider _services;

让我可以访问 Dispose() 方法,我可以优雅地告诉 ServiceProvider 我不再需要他,这样他就可以自己清理了。

文档链接: https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectioncontainerbuilderextensions.buildserviceprovider?view=dotnet-plat-ext-5.0#Microsoft_Extensions_DependencyInjection_ServiceCollectionContainerBuilder_Extensions_BuildService_IServiceCollectionBuilder_Extensions_BuildServiceProvider_IServiceCollectionBuilder_Extensions

请注意,它在 .NET Core 3.1 和 5.0 中的工作方式相同,不能对其他人保证,但我相信至少在 2.2 之前它是相同的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM