通过DI在运行时注册服务

本文关键字:注册 服务 运行时 DI 通过 | 更新日期: 2023-09-27 18:18:18

我使用的是ASP。如果你想在运行时向IServiceProvider添加一个服务,那么它就可以通过DI在整个应用程序中使用。

例如,一个简单的例子是,用户进入设置控制器并将身份验证设置从"开"更改为"关"。在该实例中,我想替换在运行时注册的服务。

设置控制器中的Psuedo代码:

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

当我在Startup.cs中这样做时,这个逻辑工作得很好,因为IServiceCollection没有被构建到IServiceProvider中。然而,我希望能够做到这一点后,启动已经执行。有人知道这是否可能吗?

通过DI在运行时注册服务

不是在运行时注册/删除服务,而是创建一个服务工厂,在运行时决定正确的服务。

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

在类中的用法:

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

这类事情在Autofac中是可能的:

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

对于。net Core,我认为这是目前唯一可能的解决方案。使用Microsoft.Extensions.DependencyInjection

创建子容器(或隔离作用域)的最佳策略

Microsoft列出了ASP不支持的特性。. NET Core DI:https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines default-service-container-replacement