.NET 6 - 将服务注入到 program.cs 中

28

我知道如何在.NET 5(或之前)的Startup.cs中进行依赖注入,但是在.NET 6中如何使用顶层的Program.cs进行相同操作呢?

.NET 5:例如,在Configure方法中,我可以注入一个类。

public class Startup
{
    public IConfiguration _configuration { get; }
    public IWebHostEnvironment _env { get; set; }

    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
        _configuration = configuration;
        _env = env;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        // TODO
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IToInjectService serviceToInject)
    {
        // USE SERVICE
    }
}

我应该如何在.NET 6中实现这个功能?

5个回答

41

使用 .Net 6 很容易。只需在配置应用程序服务之后执行 GetService 方法并运行 Build 方法即可。

WebApplication? app = builder.Build();

var someService = app.Services.GetService<ISomeService>();

someService.DoSomething();

5
有没有可能在 builder.Build() 之前得到它们? - Simone
我不知道是否可能。 - Edu_LG
1
"SomeService" 对我没用。但是 "ISomeService" 可以工作。换句话说,使用带有 GetService 方法的接口。 - thd
当然,“SomeService”是接口。这只是一个例子,一个词。 - Edu_LG
如果SomeService没有接口或者DI注册是在没有接口的情况下完成的,请使用它。(为什么要跳过接口?) 如果服务是通过接口进行DI注册的,请使用ISomeService - Zarepheth
一个小事情,但我建议使用GetRequiredService而不是GetService,或者在你的代码中处理服务可能为空的情况。 - undefined

16

您可以将您的服务添加到builder.Services集合中,然后使用以下方式访问它:

var myService = services.BuildServiceProvider().GetService<MyService>();

2
如果我没记错的话,代码应该是这样的:var myService = services.BuildServiceProvider().CreateScope().ServiceProvider.GetRequiredService<MyService>(); - Tvde1
4
因此,不建议调用BuildServiceProvider。它会创建单例服务的额外副本。 - Saturn K
1
如果这是代码中唯一的服务,那么是的,但是如果将来在应用程序/API中注册了单例服务,这会使代码受到限制。正如我所提到的,如果或更有可能,当存在单例服务时,这将创建额外的副本。这是一种反模式。 - Saturn K
1
@SaturnK 尽管如此,有些情况下你可能会发现没有其他可行的选择,而且由于 .net 中 DI 实现的不幸副作用,会导致多个单例实例缓存被调用。据我所知,所有解决方法都指向一个气味替换另一个气味,因此如果您对此有确切的解决方案,请随时在 SO 上查找相关问题并发布您的答案。 - Wim Ombelets
1
这不应该是所选答案,因为这会导致依赖项被注册两次的潜在问题。应该从已经构建的 Web 应用程序生成器 builder.Build(); 中检索此依赖项。 - Hawkzey
显示剩余6条评论

14
如果您需要在开始时使用一个作用域服务,这就是您的 program.cs 应该如何看起来:
var builder = WebApplication.CreateBuilder(args);

//Add the service
builder.Services.AddScoped<IMyDependency, MyDependency>();

var app = builder.Build();

using (var serviceScope = app.Services.CreateScope())
{
    var services = serviceScope.ServiceProvider;

    var myDependency = services.GetRequiredService<IMyDependency>();

    //Use the service
    myDependency.DoSomething();

}

app.Run();

来源: 在应用程序启动时解析服务

这对我的DbInitializer起作用了。


这是真正的答案,非常感谢。 - Paolo

6

program.cs 文件中,您可以通过 builder.Services 管理您的服务。

例如,我添加了基于 Singleton 模式和 Scoped 的 DbContext 和两个不同的服务。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddDbContext<MyDbContext>(options =>
{
    // options.UseSqlServer(...);
});
builder.Services.AddSingleton<IMyService, MyService>();
builder.Services.AddScoped<IMySessionBasedService, MySessionBasedService>();

如需更多信息,请查看ASP.NET Core 6.0中已迁移到新的最小托管模型的代码示例


1

我尝试使用GetService方法,但将服务接口类型作为输入传递(如下所示),这对我起作用了。

var app = builder.Build();    
var injectedService1 = app.Services.GetService<IToInjectService>();
injectedService1.DoSomething();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接