简体   繁体   English

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

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

I've got this small console app for which I decided to wire up Microsoft's DI so it will care of dependencies for me.我有这个小型控制台应用程序,我决定为它连接 Microsoft 的 DI,这样它就会为我处理依赖关系。 I don't have that much of a scopes, but rather transient and singleton services.我没有那么多范围,而是瞬态和 singleton 服务。

The problem is, it doesn't dispose singleton services.问题是,它不处理 singleton 服务。 Maybe it's because it doesn't know when I'm done with it?也许是因为它不知道我什么时候完成? Maybe because of some other reason.也许是因为其他一些原因。

Here's code of my static class handling injection (obviously in final app it's a bit more complex)这是我的 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.
    }
}

In Program.Main I call ServiceInjector.Configure() method, then ServiceInjector.StartScope() , then do stuff (injecting services) and in the end (in finally block of global exception handler) I call ServiceInjector.KillAllScopes() , when I want for it all to clear up.Program.Main我调用ServiceInjector.Configure()方法,然后是ServiceInjector.StartScope() ,然后做一些事情(注入服务),最后(在全局异常处理程序的finally块中)我调用ServiceInjector.KillAllScopes() ,当我想让这一切都弄清楚。 Obviously it's not enough because Dispose() of my SampleSingletonService is never called ( ISampleSingletonService inherits from IDisposable ).显然这还不够,因为我的SampleSingletonServiceDispose()从未被调用( ISampleSingletonService继承自IDisposable )。

It's a problem because I use ILoggerProvider (from another Microsoft.Extensions. package) which caches stuff and flushes it to file each few seconds.这是一个问题,因为我使用 ILoggerProvider(来自另一个Microsoft.Extensions.包)缓存内容并每隔几秒钟将其刷新到文件中。 If global exception handler finds some exception, I log it and want it to be flushed to disk, then exit the app.如果全局异常处理程序发现一些异常,我会记录它并希望将其刷新到磁盘,然后退出应用程序。 Without Dispose being called, app closes before last message can be flushed, so I loose that message.在没有调用Dispose的情况下,应用程序会在刷新最后一条消息之前关闭,因此我会丢失该消息。

I could obviously just halt the app for time longer than needed to flush to make sure it gets done, but let's just say it's not perfect solution.显然,我可以将应用程序暂停的时间比刷新所需的时间更长,以确保它完成,但我们只能说这不是完美的解决方案。

I tried somehow disposing/cleaning/closing root IServiceProvider , but it doesn't inherit from IDisposable and I none of the available methods seem to be cleaning up mess created by it.我尝试以某种方式处理/清理/关闭根IServiceProvider ,但它没有从IDisposable继承,而且我似乎没有一个可用的方法正在清理它造成的混乱。

I also tried setting _service to null and calling GC.Collect() , but Garbage Collector seemed to not being interested in helping me;)我还尝试将_service设置为 null 并调用GC.Collect() ,但垃圾收集器似乎没有兴趣帮助我;)

For the demo purpose I created minimalistic reproduction app, which shows the issue (message from Dispose method of sample service is never logged): https://github.com/domints/DotnetDISingletonDisposingPoC出于演示目的,我创建了简约的复制应用程序,它显示了问题(来自示例服务的Dispose方法的消息从未被记录): https://github.com/domints/DotnetDISingletonDisposingPoC

Thanks for any idea on how to resolve that problem.感谢您提供有关如何解决该问题的任何想法。

You need to invoke Dispose on _services field.您需要在 _services 字段上调用 Dispose。 When disposing a scope, only scoped services will be disposed, but not singletons.处置 scope 时,只会处置作用域服务,而不会处置单例。

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

I found the solution, and the culprit.我找到了解决方案,也找到了罪魁祸首。 After relooking into this question, and the docs and the code I noticed svcCollection.BuildServiceProvider() doesn't return IServiceProvider , but ServiceProvider , which implements both IServiceProvider and IDisposable .在重新研究这个问题之后,我注意到svcCollection.BuildServiceProvider()的文档和代码不返回IServiceProvider ,而是返回ServiceProvider ,它同时实现了IServiceProviderIDisposable

So changing my field to:所以将我的领域更改为:

static ServiceProvider _services;

gave me access to Dispose() method and I could gracefully tell ServiceProvider I do not need him anymore so he can clean up after himself.让我可以访问 Dispose() 方法,我可以优雅地告诉 ServiceProvider 我不再需要他,这样他就可以自己清理了。

Link to docs: https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectioncontainerbuilderextensions.buildserviceprovider?view=dotnet-plat-ext-5.0#Microsoft_Extensions_DependencyInjection_ServiceCollectionContainerBuilderExtensions_BuildServiceProvider_Microsoft_Extensions_DependencyInjection_IServiceCollection_System_Boolean _文档链接: 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

Just as a note, it works the same way in .NET Core 3.1 and 5.0, can't assure for others, but I believe it would be the same for at least up to 2.2.请注意,它在 .NET Core 3.1 和 5.0 中的工作方式相同,不能对其他人保证,但我相信至少在 2.2 之前它是相同的。

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

相关问题 Net Core 2控制台应用程序-DI&#39;无法解析类型的服务...&#39; - Net Core 2 Console App - DI 'Unable to resolve service for type…' 应用程序生命周期并在 ASP.NET 内核中添加 Singleton DI 服务 - Application Lifetime and Add Singleton DI service in ASP.NET Core .net 核心 DI 注入重复 singleton 服务用于 BuildServiceProvide - .net core DI injection duplicated singleton service for BuildServiceProvide .NET 核心 DI 允许将作用域服务注入本地机器上的 singleton - .NET Core DI allowing to inject scoped service into singleton on local machine .NET 核心 DI:无法使用来自 singleton 的范围服务 - .NET Core DI: Cannot consume scoped service from singleton .Net 5 控制台后台服务异常与 Entity Framework Core 的 DI - .Net 5 Console Background service exception with DI of Entity Framework Core 不带DI / WebHost的控制台应用程序中的.Net Core Identity SignInManager - .Net Core Identity SignInManager in Console App w/o DI/WebHost 如何在 .NET Core 控制台应用程序中设置 DI 容器? - How to setup the DI container in a .NET Core console app? .NET Core Scoped 通过 DI 在 Singleton 中调用 - .NET Core Scoped called in Singleton through DI 将 .NET Core 控制台应用程序作为服务运行,还是重做? - Running .NET Core console app as a service, or redo?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM