Dav*_*New 245 c# dependency-injection asp.net-core-mvc asp.net-core
如何使用ASP.NET Core MVC内置依赖注入框架手动解析类型?
设置容器很容易:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
Run Code Online (Sandbox Code Playgroud)
但是如何在ISomeService不进行注射的情况下解决?例如,我想这样做:
ISomeService service = services.Resolve<ISomeService>();
Run Code Online (Sandbox Code Playgroud)
没有这样的方法IServiceCollection.
Hen*_*ema 392
该IServiceCollection接口用于构建依赖注入容器.在完全构建之后,它会被组合到一个IServiceProvider可用于解析服务的实例.你可以注入IServiceProvider任何类.的IApplicationBuilder和HttpContext类可以提供所述服务提供商,以及,经由所述ApplicationServices或RequestServices分别性质.
IServiceProvider定义GetService(Type type)解析服务的方法:
var service = (IFooService)serviceProvider.GetService(typeof(IFooService));
Run Code Online (Sandbox Code Playgroud)
还有一些便利扩展方法,例如serviceProvider.GetService<IFooService>().(添加用于using).
运行时可以在Microsoft.Extensions.DependencyInjection类的构造函数中注入服务,例如Startup,IHostingEnvironment和IConfiguration.请注意,此服务提供程序是由托管层构建的实例,仅包含启动应用程序的服务.
服务也可以在IServiceProvider方法中注入.您可以在参数后添加任意数量的Configure()参数.您也可以注入自己在此IApplicationBuilder方法中注册的服务,它们将从应用程序服务提供商而不是托管服务提供商处解析.
public void Configure(IApplicationBuilder app, IFooService fooService)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
ConfigureServices()但是该方法不允许注入服务,它只接受一个ConfigureServices()参数.这是配置应用程序依赖项注入容器的方法.您可以在此处使用在启动构造函数中注入的服务.例如:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// Use Configuration here
}
Run Code Online (Sandbox Code Playgroud)
如果你想手动解决服务,可以让运行时注入一个IServiceCollection实例在构造函数或使用IServiceProvider所提供ApplicationServices的IApplicationBuilder方法:
public Startup(IServiceProvider serviceProvider)
{
var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}
Run Code Online (Sandbox Code Playgroud)
要么
public void Configure(IApplicationBuilder app)
{
var serviceProvider = app.ApplicationServices;
var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}
Run Code Online (Sandbox Code Playgroud)
但是,如果需要解析Configure()方法中的服务,则需要采用不同的方法.您可以ConfigureServices()从IServiceProvider包含在此之前注册的服务的实例构建中间件:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFooService, FooService>();
// Build the intermediate service provider
var sp = services.BuildServiceProvider();
var fooService = sp.GetService<IFooService>();
}
Run Code Online (Sandbox Code Playgroud)
你需要这个IServiceCollection包.
请注意:
通常您不应该解析Microsoft.Extensions.DependencyInjection方法中的服务,因为这实际上是您配置应用程序服务的地方.有时您只需要访问某个ConfigureServices()实例.您可以通过将IOptions<MyOptions>实例中的值绑定到实例IConfiguration(实际上是选项框架的作用)来实现此目的:
public void ConfigureServices(IServiceCollection services)
{
var myOptions = new MyOptions();
Configuration.GetSection("SomeSection").Bind(myOptions);
}
Run Code Online (Sandbox Code Playgroud)
手动解析服务(也称为服务定位器)通常被称为反模式.虽然它有用例(对于框架和/或基础架构层),但您应该尽可能地避免使用它.
Muh*_*eed 81
手动解析实例涉及使用IServiceProvider界面:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IMyService, MyService>();
var serviceProvider = services.BuildServiceProvider();
var service = serviceProvider.GetService<IMyService>();
}
Run Code Online (Sandbox Code Playgroud)
public void Configure(
IApplicationBuilder application,
IServiceProvider serviceProvider)
{
// By type.
var service1 = (MyService)serviceProvider.GetService(typeof(MyService));
// Using extension method.
var service2 = serviceProvider.GetService<MyService>();
// ...
}
Run Code Online (Sandbox Code Playgroud)
某些类型可以作为方法参数注入:
public class Startup
{
public Startup(
IHostingEnvironment hostingEnvironment,
ILoggerFactory loggerFactory)
{
}
public void ConfigureServices(
IServiceCollection services)
{
}
public void Configure(
IApplicationBuilder application,
IHostingEnvironment hostingEnvironment,
IServiceProvider serviceProvider,
ILoggerFactory loggerfactory,
IApplicationLifetime applicationLifetime)
{
}
}
Run Code Online (Sandbox Code Playgroud)
[HttpGet("/some-action")]
public string SomeAction([FromServices] IMyService myService) => "Hello";
Run Code Online (Sandbox Code Playgroud)
Bru*_*oLM 14
如果您使用模板生成应用程序,那么您将在Startup类中使用以下内容:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以在那里添加依赖项,例如:
services.AddTransient<ITestService, TestService>();
Run Code Online (Sandbox Code Playgroud)
如果你想ITestService在你的控制器上访问你可以添加IServiceProvider构造函数,它将被注入:
public HomeController(IServiceProvider serviceProvider)
Run Code Online (Sandbox Code Playgroud)
然后,您可以解决您添加的服务:
var service = serviceProvider.GetService<ITestService>();
Run Code Online (Sandbox Code Playgroud)
请注意,要使用通用版本,您必须包含带有扩展名的命名空间:
using Microsoft.Extensions.DependencyInjection;
Run Code Online (Sandbox Code Playgroud)
ITestService.cs
public interface ITestService
{
int GenerateRandom();
}
Run Code Online (Sandbox Code Playgroud)
TestService.cs
public class TestService : ITestService
{
public int GenerateRandom()
{
return 4;
}
}
Run Code Online (Sandbox Code Playgroud)
Startup.cs(ConfigureServices)
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
services.AddTransient<ITestService, TestService>();
}
Run Code Online (Sandbox Code Playgroud)
HomeController.cs
using Microsoft.Extensions.DependencyInjection;
namespace Core.Controllers
{
public class HomeController : Controller
{
public HomeController(IServiceProvider serviceProvider)
{
var service = serviceProvider.GetService<ITestService>();
int rnd = service.GenerateRandom();
}
Run Code Online (Sandbox Code Playgroud)
您可以通过这种方式在 AuthorizeAttribute 等属性中注入依赖项
var someservice = (ISomeService)context.HttpContext.RequestServices.GetService(typeof(ISomeService));
Run Code Online (Sandbox Code Playgroud)
如果只需要解析一个依赖项以将其传递给正在注册的另一个依赖项的构造函数,则可以执行此操作。
假设您有一个接受字符串和ISomeService的服务。
public class AnotherService : IAnotherService
{
public AnotherService(ISomeService someService, string serviceUrl)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
当您在Startup.cs中进行注册时,您需要执行以下操作:
services.AddScoped<IAnotherService>(ctx =>
new AnotherService(ctx.GetService<ISomeService>(), "https://someservice.com/")
);
Run Code Online (Sandbox Code Playgroud)
我知道这是一个老问题,但我很惊讶这里没有一个相当明显和令人作呕的黑客。
您可以利用定义自己的 ctor 函数的能力,在定义服务时从服务中获取必要的值……显然,除非您明确删除/清除并重新添加服务的定义,否则每次请求服务时都会运行这项服务在开发 ctor 的第一个建设中。
此方法的优点是不需要您在配置服务期间构建或使用服务树。您仍在定义如何配置服务。
public void ConfigureServices(IServiceCollection services)
{
//Prey this doesn't get GC'd or promote to a static class var
string? somevalue = null;
services.AddSingleton<IServiceINeedToUse, ServiceINeedToUse>(scope => {
//create service you need
var service = new ServiceINeedToUse(scope.GetService<IDependantService>())
//get the values you need
somevalue = somevalue ?? service.MyDirtyHack();
//return the instance
return service;
});
services.AddTransient<IOtherService, OtherService>(scope => {
//Explicitly ensuring the ctor function above is called, and also showcasing why this is an anti-pattern.
scope.GetService<IServiceINeedToUse>();
//TODO: Clean up both the IServiceINeedToUse and IOtherService configuration here, then somehow rebuild the service tree.
//Wow!
return new OtherService(somevalue);
});
}
Run Code Online (Sandbox Code Playgroud)
修复此模式的方法是对 提供OtherService显式依赖IServiceINeedToUse,而不是隐式依赖于它或其方法的返回值……或以其他方式显式解析该依赖。
| 归档时间: |
|
| 查看次数: |
173355 次 |
| 最近记录: |