简体   繁体   中英

Register Service at Runtime via DI?

I am using ASP.NET Core and want to add a service to the IServiceProvider at runtime, so it can be used across the application via DI.

For instance, a simple example would be that the user goes to the settings controller and changes an authentication setting from "On" to "Off". In that instance I would like to replace the service that was registered at runtime.

Psuedo Code in the Settings Controller:

if(settings.Authentication == false)
{
     services.Remove(ServiceDescriptor.Transient<IAuthenticationService, AuthenticationService>());
     services.Add(ServiceDescriptor.Transient<IAuthenticationService, NoAuthService>());
}
else
{
     services.Remove(ServiceDescriptor.Transient<IAuthenticationService, NoAuthService>
     services.Add(ServiceDescriptor.Transient<IAuthenticationService, AuthenticationService>());
}

This logic works fine when I am doing it in my Startup.cs because the IServiceCollection has not been built into a IServiceProvider. However, I want to be able to do this after the Startup has already executed. Does anyone know if this is even possible?

Instead of registering/removing service at runtime, i would create a service factory which decides right service at runtime.

services.AddTransient<AuthenticationService>();
services.AddTransient<NoAuthService>();
services.AddTransient<IAuthenticationServiceFactory, AuthenticationServiceFactory>();

AuthenticationServiceFactory.cs

public class AuthenticationServiceFactory: IAuthenticationServiceFactory
{
     private readonly AuthenticationService _authenticationService;
     private readonly NoAuthService_noAuthService;
     public AuthenticationServiceFactory(AuthenticationService authenticationService, NoAuthService noAuthService)
     {
         _noAuthService = noAuthService;
         _authenticationService = authenticationService;
     }
     public IAuthenticationService GetAuthenticationService()
     {
          if(settings.Authentication == false)
          {
             return _noAuthService;
          }
          else
          {
              return _authenticationService;
          }
     }
}

Usage in a class:

public class SomeClass
{
    public SomeClass(IAuthenticationServiceFactory _authenticationServiceFactory)
    {
        var authenticationService = _authenticationServiceFactory.GetAuthenticationService();
    }
}

Something of the sort is possible in Autofac:

  private ILifetimeScope BeginChildScope()
  {
        return _lifetimeScope.BeginLifetimeScope(x =>
        {
            x.Register<IAuthenticationService>(b => new AuthenticationService());
        });
  }
using (var childScope = BeginChildScope())
{
   // Do sth here
}

For .NET Core, I think this is the only possible solution atm.: Best strategy for creating a child container (or isolated scope) with Microsoft.Extensions.DependencyInjection

Microsoft states unsupported features of ASP.NET Core DI here: https://learn.microsoft.com/en-us/do.net/core/extensions/dependency-injection-guidelines#default-service-container-replacement

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM