How to configure services based on request in ASP.NET Core

I'm afraid you can not directly acheive the goal via simple dependency injection , as the the dependency injection configured at Startup stage , in other words , all services and implementions has been configured before a request comming .

However , you can inject a Create Service delegate so that can we create the required service implemention instance in runtime .

For instance , if we have a IReportFactory Interface and two implementions as blew :

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

As we want to get the required implemention in future , we need to register the Implementions first .

services.AddScoped<ReportFactory1>();
services.AddScoped<ReportFactory2>();

and here's where the magic happens :

  1. We don't register a IReportFactory
  2. We just add a Func<HttpContext,IReportFactory> instead , which is a CreateReportFactoryDelegate

    public delegate IReportFactory CreateReportFactoryDelegate(Microsoft.AspNetCore.Http.HttpContext context);

We need add the CreateReportFactoryDelegate to servies too.

services.AddScoped<CreateReportFactoryDelegate>(sp => {
    // return the required implemention service by the context;
    return context => {
        // now we have the http context ,
        // we can decide which factory implemention should be returned;
        // ...
        if (context.Request.Path.ToString().Contains("factory1")) {
            return sp.GetRequiredService<ReportFactory1>();
        }
        return sp.GetRequiredService<ReportFactory2>();
    };
});

Now , we can inject a CreateReportFactoryDelegate into controller :

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

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