![](/img/trans.png)
[英]Net Core 2 Console App - DI 'Unable to resolve service for type…'
[英].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()
,當我想讓這一切都弄清楚。 顯然這還不夠,因為我的SampleSingletonService
的Dispose()
從未被調用( 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
,它同時實現了IServiceProvider
和IDisposable
。
所以將我的領域更改為:
static ServiceProvider _services;
讓我可以訪問 Dispose() 方法,我可以優雅地告訴 ServiceProvider 我不再需要他,這樣他就可以自己清理了。
請注意,它在 .NET Core 3.1 和 5.0 中的工作方式相同,不能對其他人保證,但我相信至少在 2.2 之前它是相同的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.