C# .NET核心DI-在控制台应用程序中处理单例服务

C# .NET核心DI-在控制台应用程序中处理单例服务,c#,.net-core,dependency-injection,singleton,console-application,C#,.net Core,Dependency Injection,Singleton,Console Application,我有一个小的控制台应用程序,我决定为它连接微软的DI,这样它就可以为我处理依赖关系。我没有那么多的作用域,而是临时和单例服务 问题是,它不处理单例服务。也许是因为它不知道我什么时候做完?也许是因为其他原因 下面是我的静态类处理注入的代码(显然在最终的应用程序中它有点复杂) 公共静态类ServiceInjector { 静态IServiceProvider_服务; 静态堆栈_scopeStack; 静态IServiceProvider\u provider=>\u scopeStack.NullP

我有一个小的控制台应用程序,我决定为它连接微软的DI,这样它就可以为我处理依赖关系。我没有那么多的作用域,而是临时和单例服务

问题是,它不处理单例服务。也许是因为它不知道我什么时候做完?也许是因为其他原因

下面是我的静态类处理注入的代码(显然在最终的应用程序中它有点复杂)

公共静态类ServiceInjector
{
静态IServiceProvider_服务;
静态堆栈_scopeStack;
静态IServiceProvider\u provider=>\u scopeStack.NullPeek()?.ServiceProvider\u服务;
公共静态void Configure()
{
var svcCollection=newservicecolection();
svcCollection.AddSingleton();
_services=svcCollection.BuildServiceProvider();
_scopeStack=新堆栈();
}
公共静态T GetService()
{
返回_provider.GetService();
}
公共静态void StartScope()
{
_Push(_services.CreateScope());
}
公共静态void KillAllScopes()
{
while(_scopeStack.TryPop(out IServiceScope scope))
{
scope.Dispose();
}
_services=null;//我还试图说服GC清理并强制Dispose.Nope。
}
}
Program.Main
中,我调用
ServiceInjector.Configure()
方法,然后调用
ServiceInjector.StartScope()
,然后执行一些操作(注入服务),最后(在全局异常处理程序的
最后
块中)调用
ServiceInjector.KillAllScopes()
,当我想清除所有异常时。 显然这还不够,因为从未调用我的
SampleSingletonService
Dispose()
ISampleSingletonService
继承自
IDisposable

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

很明显,我可以暂停应用程序的时间超过刷新所需的时间,以确保它完成,但我们只能说这不是完美的解决方案

我试图以某种方式处理/清理/关闭根
IServiceProvider
,但它并没有继承自
IDisposable
,而且我发现任何可用的方法似乎都无法清理它造成的混乱

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

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


谢谢你提出解决这个问题的办法。

我找到了解决办法,找到了罪魁祸首。在重新阅读这个问题之后,我注意到的文档和代码
svcCollection.BuildServiceProvider()
没有返回
IServiceProvider
,而是
ServiceProvider
,它实现了
IServiceProvider
IDisposable

因此,将我的字段更改为:

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

链接到文档:_


值得注意的是,它在.NET Core 3.1和5.0中的工作方式是相同的,不能为其他人保证,但我相信至少在2.2中也是一样的。

我找到了解决方案,找到了罪魁祸首。在重新阅读这个问题之后,我注意到的文档和代码
svcCollection.BuildServiceProvider()
没有返回
IServiceProvider
,而是
ServiceProvider
,它实现了
IServiceProvider
IDisposable

因此,将我的字段更改为:

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

链接到文档:_


需要注意的是,它在.NET Core 3.1和5.0中的工作方式是相同的,不能保证其他版本的工作方式,但我相信至少在2.2中也是一样的。

您需要在“服务”字段中调用Dispose。 处理作用域时,只处理作用域服务,而不处理单例服务

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

您需要在_services字段中调用Dispose。 处理作用域时,只处理作用域服务,而不处理单例服务

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

@启示录我见过,但问题是他们使用HostBuilder来管理服务提供商的生命周期。我自己创建了ServiceProvider(使用
BuildServiceProvider
方法),所以这个场景对我来说不是很好。Host builder是为这样的场景设计的。使用它来创建自定义逻辑是很好的。@启示录我见过它,但问题是他们使用HostBuilder来管理ServiceProvider的生命周期。我自己创建了ServiceProvider(使用
BuildServiceProvider
方法),所以这个场景对我来说不是很好。Host builder是为这样的场景设计的。在创建自定义逻辑时使用它是很好的。这是真的,但问题是,_services字段是IServiceProvider,它不包含IDisposable。这就是让我不高兴的地方。尽管如此,谢谢。这是真的,但事实是,_services字段是IServiceProvider,它不包含IDisposable。这就是让我不高兴的地方。不过,谢谢你。