如何在ASP.NET Core中根据请求配置服务 [英] How to configure services based on request in ASP.NET Core

查看:153
本文介绍了如何在ASP.NET Core中根据请求配置服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在ASP.NET Core中,我们可以在启动过程中注册所有依赖项,这些依赖项在应用程序启动时执行.然后将注册的依赖项注入到控制器构造函数中.

In ASP.NET Core we can register all dependencies during start up, which executed when application starts. Then registered dependencies will be injected in controller constructor.

public class ReportController
{
    private IReportFactory _reportFactory;

    public ReportController(IReportFactory reportFactory)
    {
        _reportFactory = reportFactory;
    }

    public IActionResult Get()
    {
        vart report = _reportFactory.Create();
        return Ok(report);
    }
}

现在,我想基于当前请求中的数据(用户授权级别或与请求一起传递的查询字符串中的某些值)注入IReportFactory的不同实现.

Now I want to inject different implementations of IReportFactory based on data in current request (User authorization level or some value in the querystring passed with an request).

问题:ASP.NET Core中是否有任何内置的抽象(中间件),我们可以在其中注册接口的另一种实现?

Question: is there any built-in abstraction(middleware) in ASP.NET Core where we can register another implementation of interface?

如果没有内置功能,可能的解决方法是什么?

What is the possible approach for this if there no built-in features?

更新 IReportFactory接口用作一个简单示例.实际上,我在不同位置注入了一堆低级接口.现在我希望根据请求数据注入那些低级接口的不同实现.

Update IReportFactory interface was used as a simple example. Actually I have bunch of low level interfaces injected in different places. And now I want that different implementation of those low level interfaces will be injected based on request data.

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;
    }
 }  

因为我们知道需要在应用程序的入口点使用哪种实现(我认为控制器动作可以视为应用程序的入口点),所以我们希望在此处注入正确的实现-在现有设计中无需进行任何更改.

Because we know which implementation we need to use on entry point of our application (I think controller action can be considered as entry point of application), we want inject correct implementation already there - no changes required in already existed design.

推荐答案

不,您不能.在应用程序启动期间填充IServiceCollection,并在调用Configure方法之前对其进行构建.此后(正在构建容器),无法再更改注册.

No, you can't. The IServiceCollection is populated during application startup and built before Configure method is called. After that (container being built), the registrations can't be changed anymore.

但是,您可以实现抽象工厂,无论是作为工厂方法还是作为接口/类.

You can however implement an abstract factory, be it as factory method or as an interface/class.

// 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>()
});

或者使用 查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆