C# 一次又一次地构建服务提供商可以吗?
在.NET核心控制台应用程序中,我希望使用内置的依赖项注入,包括自动处理链中的C# 一次又一次地构建服务提供商可以吗?,c#,.net-core,dependency-injection,C#,.net Core,Dependency Injection,在.NET核心控制台应用程序中,我希望使用内置的依赖项注入,包括自动处理链中的IDisposable对象。在ASP.NET内核中,对象是随着每个请求创建和处理的,这似乎是合理的 但在控制台应用程序中,我必须构建服务提供商,然后通过从提供商检索链中的第一项并运行以下命令来启动它: class Program { static void Main() { using var serviceProvider = new ServiceCollection()
IDisposable
对象。在ASP.NET内核中,对象是随着每个请求创建和处理的,这似乎是合理的
但在控制台应用程序中,我必须构建服务提供商,然后通过从提供商检索链中的第一项并运行以下命令来启动它:
class Program {
static void Main() {
using var serviceProvider = new ServiceCollection()
.AddTransient<Program>()
.AddTransient<Repository>()
.AddTransient<MyContext>()
.BuildServiceProvider();
serviceProvider.GetService<Program>().Go();
}
private readonly Repository _repo;
public Program(Repository repo) => _repo = repo;
public void Go() => _repo.Go();
}
public class Repository : IDisposable {
private readonly MyContext _context;
public Repository(MyContext context) => _context = context;
public void Go() => Console.WriteLine("Go!");
public void Dispose() => Console.WriteLine("Repository Disposed!");
}
public class MyContext : DbContext {
public override void Dispose() {
base.Dispose();
Console.WriteLine("MyContext Disposed!");
}
}
如果我希望在循环中或使用计时器运行进程,则在服务提供程序本身被释放之前,不会释放任何内容:
for (int i = 0; i < 3; ++i)
{
serviceProvider.GetService<Program>().Go();
}
Go!
Go!
Go!
Repository Disposed!
MyContext Disposed!
Repository Disposed!
MyContext Disposed!
Repository Disposed!
MyContext Disposed!
for(int i=0;i<3;++i)
{
serviceProvider.GetService().Go();
}
走!
走!
走!
处置库!
MyContext!
处置库!
MyContext!
处置库!
MyContext!
如果我每次都处置并重新创建服务提供商,我会得到想要的结果:
for (int i = 0; i < 3; ++i)
{
using var serviceProvider = new ServiceCollection()
.AddTransient<Program>()
.AddTransient<Repository>()
.AddTransient<MyContext>()
.BuildServiceProvider();
serviceProvider.GetService<Program>().Go();
}
Go!
Repository Disposed!
MyContext Disposed!
Go!
Repository Disposed!
MyContext Disposed!
Go!
Repository Disposed!
MyContext Disposed!
for(int i=0;i<3;++i)
{
使用var serviceProvider=newservicecollection()
.AddTransient()
.AddTransient()
.AddTransient()
.BuildServiceProvider();
serviceProvider.GetService().Go();
}
走!
处置库!
MyContext!
走!
处置库!
MyContext!
走!
处置库!
MyContext!
我的问题:像这样一次又一次地构建和处理提供者可以吗?我在考虑每隔几秒钟用定时器做一次。这是一个昂贵的过程吗?有没有更好的方法,不必在整个链中手动处理对象
或者这可能就是ASP.NET Core在幕后所做的,用每个请求重新创建提供程序吗?简言之,不!我绝对不会每次都重新创建服务提供商。这似乎相当浪费 不,ASP.NETDI不是这样工作的,服务提供程序只在应用程序启动时构建 如果将
Program
更改为实现IDisposable
,并将循环更改为
for(int i=0;i<3;++i)
{
使用(var program=serviceProvider.GetService()){
program.Go();
}
}
你应该得到同样的结果
未测试的垃圾收集将在适当的时候处理注入对象,因此您不必担心。创建您可以使用的静态服务提供商:
static void Main() {
serviceProvider = new ServiceCollection()
.AddTransient<Program>()
.AddTransient<Repository>()
.AddTransient<MyContext>()
.BuildServiceProvider();
serviceProvider.GetService<Program>().Go();
}
private static IServiceProvider serviceProvider;
static void Main(){
serviceProvider=新的ServiceCollection()
.AddTransient()
.AddTransient()
.AddTransient()
.BuildServiceProvider();
serviceProvider.GetService().Go();
}
专用静态IServiceProvider服务提供商;
创建一个作用域,从中解析所有依赖项,然后处置该作用域。看起来是这样的:
using var serviceProvider = new ServiceCollection()
.AddTransient<Program>()
.AddTransient<Repository>()
.AddTransient<MyContext>()
.BuildServiceProvider();
for (int i = 0; i < 3; ++i)
{
using var scope = serviceProvider.CreateScope();
scope.ServiceProvider.GetService<Program>().Go();
}
使用var serviceProvider=new servicecolection()
.AddTransient()
.AddTransient()
.AddTransient()
.BuildServiceProvider();
对于(int i=0;i<3;++i)
{
使用var scope=serviceProvider.CreateScope();
scope.ServiceProvider.GetService().Go();
}
当服务作用域本身被释放时,服务作用域创建的所有作用域服务和临时服务都被释放。在本例中,所有涉及的服务都注册为transient,这意味着每次请求
程序时都会创建新实例。如果您要从同一服务范围多次请求Program
,您将获得所有所需注册服务的多个实例。这些实例中的每一个都由服务范围跟踪,并与服务范围一起处理。如果您更改serviceProvider.GetService().Go()使用(var program=serviceProvider.GetService()){program.Go();}
您应该得到相同的结果-UNTESTEDProgram不是一次性的。另外,我只是试着让它成为一次性的,然后这样做,直到服务提供商被处理掉,它仍然不会处理孩子。它实际上是双重处理程序-一次是在使用
完成时,另一次是在处理提供者时。这与我最初的示例没有什么不同-如果我继续使用相同的服务提供者
而不处理它,那么其他对象都不会在我需要时被处理。我不想把它留给垃圾收集器-我想在处理完这些对象后正确地处理它们。@JoeEnos你可以调用。处理完你的一次性对象后再处理它?DI会为你做这件事,所以手动处理需要在每个项目上实现一次性,手动处理每个项目的子项,这是我试图避免的。但是,是的,如果我需要对处理过程进行超粒度控制,我可以做到。好主意。当您使用(var scope=serviceProvider.CreateScope()){scope.serviceProvider.GetService().Go();}
将代码更改为时,它也可以在没有循环的情况下工作。
using var serviceProvider = new ServiceCollection()
.AddTransient<Program>()
.AddTransient<Repository>()
.AddTransient<MyContext>()
.BuildServiceProvider();
for (int i = 0; i < 3; ++i)
{
using var scope = serviceProvider.CreateScope();
scope.ServiceProvider.GetService<Program>().Go();
}