Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure services based on request in 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);
    }
}

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).

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?

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.

like image 544
Basin Avatar asked Aug 01 '18 05:08

Basin


People also ask

How do I configure services in NET Core?

The ConfigureServices method is a place where you can register your dependent classes with the built-in IoC container. After registering dependent class, it can be used anywhere in the application. You just need to include it in the parameter of the constructor of a class where you want to use it.

How does ASP.NET Core process a request?

The ASP.NET Core web server will convert the response from the application logic into a raw HTTP response and sends it back to the reverse proxy. The reverse proxy will then send it back to the browser.

Can we configure service and request pipeline without defining startup class?

To configure services and the request processing pipeline without using a Startup class, call ConfigureServices and Configure convenience methods on the host builder. Multiple calls to ConfigureServices append to one another.


1 Answers

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

Alternatively use an abstract factory class

like image 164
Tseng Avatar answered Oct 19 '22 02:10

Tseng