簡體   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