C# 如何在ASP.NET内核中基于请求配置服务
在ASP.NET Core中,我们可以在启动期间注册所有依赖项,这些依赖项在应用程序启动时执行。然后,注册的依赖项将被注入控制器构造函数中C# 如何在ASP.NET内核中基于请求配置服务,c#,asp.net-core,dependency-injection,C#,Asp.net Core,Dependency Injection,在ASP.NET Core中,我们可以在启动期间注册所有依赖项,这些依赖项在应用程序启动时执行。然后,注册的依赖项将被注入控制器构造函数中 public class ReportController { private IReportFactory _reportFactory; public ReportController(IReportFactory reportFactory) { _reportFactory = reportFactory;
public class ReportController
{
private IReportFactory _reportFactory;
public ReportController(IReportFactory reportFactory)
{
_reportFactory = reportFactory;
}
public IActionResult Get()
{
vart report = _reportFactory.Create();
return Ok(report);
}
}
现在,我想根据当前请求中的数据(用户授权级别或随请求传递的querystring中的某个值)注入不同的IReportFactory
实现
问:ASP.NET核心中是否有内置的抽象(中间件),我们可以在其中注册接口的另一个实现
如果没有内置功能,可能的方法是什么
更新
IReportFactory
接口被用作一个简单的示例。实际上,我在不同的地方注入了大量的低级接口。现在,我希望基于请求数据注入这些低级接口的不同实现
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService;
}
public IActionResult Create()
{
var order = _orderService.Create();
return Ok(order);
}
}
public class OrderService
{
private OrderBuilder _orderBuilder;
private IShippingService _shippingService; // This now have many different implementations
public OrderService(
OrderBuilder _orderBuilder,
IShippingService _shippingService)
{
_orderService = orderService;
_shippingService = shippingService;
}
public Order Create()
{
var order = _orderBuilder.Build();
var order.ShippingInfo = _shippingService.Ship();
return order;
}
}
因为我们知道我们需要在应用程序的入口点上使用哪个实现(我认为控制器操作可以被视为应用程序的入口点),所以我们希望已经在那个里注入正确的实现-在已经存在的设计中不需要更改。不,你们不能。
IServiceCollection
在应用程序启动期间填充,并在调用Configure
方法之前构建。在此之后(容器被构建),注册不能再被更改
但是,您可以实现抽象工厂,无论是作为工厂方法还是作为接口/类
// Its required to register the IHttpContextAccessor first
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IReportService>(provider => {
var httpContext = provider.GetRequired<IHttpContextAccessor>().HttpContext;
if(httpContext.User.IsAuthorized)
{
return new AuthorizedUserReportService(...);
// or resolve it provider.GetService<AuthorizedUserReportService>()
}
return new AnonymousUserReportService(...);
// or resolve it provider.GetService<AnonymousUserReportService>()
});
//需要先注册IHttpContextAccessor
services.AddSingleton();
services.AddScoped(provider=>{
var httpContext=provider.GetRequired().httpContext;
if(httpContext.User.IsAuthorized)
{
返回新的AuthorizedUserReportService(…);
//或者解析it provider.GetService恐怕您无法通过简单的依赖注入直接实现目标,因为在启动阶段配置的依赖注入,换句话说,所有服务和实现都是在请求提交之前配置的
但是,您可以注入一个createservice委托,这样我们就可以在运行时创建所需的服务实现实例
例如,如果我们有一个IReportFactory
接口和两个实现,如下所示:
public interface IReportFactory
{
object Create();
}
public class ReportFactory1 : IReportFactory
{
public object Create()
{
return new { F = 1, };
}
}
public class ReportFactory2 : IReportFactory {
public object Create()
{
return new { F = 2, };
}
}
由于我们希望在将来获得所需的实现,我们需要首先注册这些实现
services.AddScoped<ReportFactory1>();
services.AddScoped<ReportFactory2>();
现在,我们可以将CreateReportFactoryDelegate
注入控制器:
public class HomeController : Controller
{
private CreateReportFactoryDelegate _createReportFactoryDelegate;
public HomeController(CreateReportFactoryDelegate createDelegate) {
this._createReportFactoryDelegate = createDelegate;
// ...
}
public async Task<IActionResult> CacheGetOrCreateAsync() {
IReportFactory reportFactory = this._createReportFactoryDelegate(this.HttpContext);
var x=reportFactory.Create();
// ...
return View("Cache", cacheEntry);
}
}
公共类HomeController:控制器
{
私有CreateReportFactoryDelegate _CreateReportFactoryDelegate;
公共HomeController(CreateReportFactoryDelegate createDelegate){
这。_createReportFactoryDelegate=createDelegate;
// ...
}
公共异步任务cacheGetOrCreateAync(){
IReportFactory reportFactory=this.\u createReportFactoryDelegate(this.HttpContext);
var x=reportFactory.Create();
// ...
返回视图(“缓存”,cacheEntry);
}
}
可以在Startup.cs中使用HttpContextAccessor
services.AddHttpContextAccessor();
services.AddScoped<IYourService>(provider =>
{
var contextAccessor = provider.GetService<IHttpContextAccessor>();
var httpContext = contextAccessor.HttpContext;
var contextVariable = httpContext. ...
// Return implementation of IYourService that corresponds to your contextVariable
});
services.AddHttpContextAccessor();
services.AddScoped(provider=>
{
var contextAccessor=provider.GetService();
var httpContext=contextAccessor.httpContext;
var contextVariable=httpContext。。。
//返回与contextVariable对应的IYourService的实现
});
您已经有了工厂。使用带有参数的工厂方法Create
来检索特定实例。如果您需要有不同的工厂(为什么?)然后,您可以使用抽象工厂模式。您可以注册同一接口的多个实现,您将得到一个IEnumerable
注入。如果创建AuthorizedUserReportService
implementsIDisposed
,ASP.NET Core会在退出作用域时自动处理它,还是应该手动处理(如何处理?)?它应该可以工作,但只能说看了代码一次。但我现在正在工作的路上,它应该被处理。毕竟,这是一个工厂方法,它只告诉它是如何实例化的,而不告诉它的生命周期(注册方法就是这样做的,AddScoped
/AddTransient
/AddSingleton
)一些DI框架可以在构建服务提供商后进行注册。然后,您可以在中间件中注册新的依赖项。例如,DryIoC可以这样做。但这需要对现有项目进行重大更改。请注意:使用服务更为清晰。AddHttpContextAccessor();扩展方法而不是services.AddSingleton();
services.AddHttpContextAccessor();
services.AddScoped<IYourService>(provider =>
{
var contextAccessor = provider.GetService<IHttpContextAccessor>();
var httpContext = contextAccessor.HttpContext;
var contextVariable = httpContext. ...
// Return implementation of IYourService that corresponds to your contextVariable
});