【发布时间】:2021-03-15 18:17:33
【问题描述】:
我有这个小型控制台应用程序,我决定为它连接 Microsoft 的 DI,这样它就会为我处理依赖关系。我没有那么多范围,而是瞬态和单例服务。
问题是,它不处理单例服务。也许是因为它不知道我什么时候完成它?也许是因为其他原因。
这是我的静态类处理注入的代码(显然在最终应用中它有点复杂)
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
感谢您提供有关如何解决该问题的任何想法。
【问题讨论】:
-
@apocalypse 我见过,但问题是他们使用 HostBuilder 以某种方式管理 ServiceProvider 的生命周期。我自己创建了 ServiceProvider(使用
BuildServiceProvider方法),所以这个场景对我来说效果不太好。 -
主机生成器专为此类场景而设计。最好使用它来创建自定义逻辑。
标签: c# .net-core dependency-injection singleton console-application