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

后端 未结 3 2126
一个人的身影
一个人的身影 2021-02-09 02:33

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

相关标签:
3条回答
  • 2021-02-09 02:44

    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

    0 讨论(0)
  • 2021-02-09 02:45

    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);
        }
    }
    
    0 讨论(0)
  • 2021-02-09 02:56

    It is possible by using the HttpContextAccessor in Startup.cs

    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
    
                  
                });
    
    0 讨论(0)
提交回复
热议问题