本文介绍了在ConfigureServices中使用ASP.NET Core DI解决实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用ASP.NET Core MVC内置的依赖项注入框架手动解析类型?

How do I manually resolve a type using the ASP.NET Core MVC built-in dependency injection framework?

设置容器非常简单:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddTransient<ISomeService, SomeConcreteService>();
}

但是如何在不执行注入的情况下解决ISomeService?例如,我要这样做:

But how can I resolve ISomeService without performing injection? For example, I want to do this:

ISomeService service = services.Resolve<ISomeService>();

IServiceCollection中没有此类方法.

推荐答案

IServiceCollection 接口用于构建依赖项注入容器.完全构建后,将组成一个 IServiceProvider 您可以用来解析服务的实例.您可以将IServiceProvider注入到任何类中. IApplicationBuilderHttpContext类也可以通过其 ApplicationServices RequestServices 属性.

The IServiceCollection interface is used for building a dependency injection container. After it's fully built, it gets composed to an IServiceProvider instance which you can use to resolve services. You can inject an IServiceProvider into any class. The IApplicationBuilder and HttpContext classes can provide the service provider as well, via their ApplicationServices or RequestServices properties respectively.

IServiceProvider定义了 GetService(Type type) 解决服务的方法:

IServiceProvider defines a GetService(Type type) method to resolve a service:

var service = (IFooService)serviceProvider.GetService(typeof(IFooService));

也有几种便利扩展方法,例如 serviceProvider.GetService<IFooService>() (为Microsoft.Extensions.DependencyInjection添加using).

There are also several convenience extension methods available, such as serviceProvider.GetService<IFooService>() (add a using for Microsoft.Extensions.DependencyInjection).

运行时的托管服务提供程序可以将某些服务注入到Startup类的构造函数中,例如 IConfiguration IWebHostEnvironment (IHostingEnvironment -3.0版本), ILoggerFactory IServiceProvider.请注意,后者是由托管层构建的实例,并且仅包含用于启动应用程序的基本服务.

The runtime's hosting service provider can inject certain services into the constructor of the Startup class, such as IConfiguration,IWebHostEnvironment (IHostingEnvironment in pre-3.0 versions), ILoggerFactory and IServiceProvider. Note that the latter is an instance built by the hosting layer and contains only the essential services for starting up an application.

ConfigureServices()方法不允许注入服务,它仅接受IServiceCollection自变量.这是有道理的,因为ConfigureServices()是您注册应用程序所需服务的位置.但是,您可以在此处使用注入到启动程序的构造函数中的服务,例如:

The ConfigureServices() method does not allow injecting services, it only accepts an IServiceCollection argument. This makes sense because ConfigureServices() is where you register the services required by your application. However you can use services injected in the startup's constructor here, for example:

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // Use Configuration here
}

然后,可以将在ConfigureServices()中注册的任何服务注入到Configure()方法中;您可以在IApplicationBuilder参数之后添加任意数量的服务:

Any services registered in ConfigureServices() can then be injected into the Configure() method; you can add an arbitrary number of services after the IApplicationBuilder parameter:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IFooService>();
}

public void Configure(IApplicationBuilder app, IFooService fooService)
{
    fooService.Bar();
}

手动解决依赖性

如果需要手动解析服务,则最好在Configure()方法中使用IApplicationBuilder提供的ApplicationServices:

Manually resolving dependencies

If you need to manually resolve services, you should preferably use the ApplicationServices provided by IApplicationBuilder in the Configure() method:

public void Configure(IApplicationBuilder app)
{
    var serviceProvider = app.ApplicationServices;
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}

可以在您的Startup类的构造函数中传递并直接使用IServiceProvider,但是如上所述,它将包含有限的服务子集,因此实用程序有限:

It is possible to pass and directly use an IServiceProvider in the constructor of your Startup class, but as above this will contain a limited subset of services, and thus has limited utility:

public Startup(IServiceProvider serviceProvider)
{
    var hostingEnv = serviceProvider.GetService<IWebHostEnvironment>();
}

如果必须使用ConfigureServices()方法解析服务,则需要另一种方法.您可以从IServiceCollection实例构建中间IServiceProvider,该实例包含到那时为止已注册的服务:

If you must resolve services in the ConfigureServices() method, a different approach is required. You can build an intermediate IServiceProvider from the IServiceCollection instance which contains the services which have been registered up to that point:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFooService, FooService>();

    // Build the intermediate service provider
    var sp = services.BuildServiceProvider();

    // This will succeed.
    var fooService = sp.GetService<IFooService>();
    // This will fail (return null), as IBarService hasn't been registered yet.
    var barService = sp.GetService<IBarService>();
}

请注意:通常,您应该避免在ConfigureServices()方法内部解析服务,因为实际上这是您配置应用程序服务的地方.有时您只需要访问IOptions<MyOptions>实例.您可以通过将IConfiguration实例中的值绑定到MyOptions实例(实质上是选项框架所做的事情)来实现此目的:

Please note:Generally you should avoid resolving services inside the ConfigureServices() method, as this is actually the place where you're configuring the application services. Sometimes you just need access to an IOptions<MyOptions> instance. You can accomplish this by binding the values from the IConfiguration instance to an instance of MyOptions (which is essentially what the options framework does):

public void ConfigureServices(IServiceCollection services)
{
    var myOptions = new MyOptions();
    Configuration.GetSection("SomeSection").Bind(myOptions);
}

手动解析服务(又称为服务定位器)为通常被认为是反模式.尽管有其用例(用于框架和/或基础结构层),但您应尽可能避免使用它.

Manually resolving services (aka Service Locator) is generally considered an anti-pattern. While it has its use-cases (for frameworks and/or infrastructure layers), you should avoid it as much as possible.

这篇关于在ConfigureServices中使用ASP.NET Core DI解决实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 00:22