2

我有一个用例(带有登录的应用程序,然后是具有不同功能的各种页面进行导航),我在ConfigureServices方法中注册了我的大部分服务(就像通常那样),因此在我的实际(UI)执行之前程序。

然而,我有一些服务,我只注册为假人(甚至根本不注册),因为这些服务应该在我登录到 Web 服务后才设置。在这个登录过程中,不仅检查用户是否有效,而且在用户验证后得到各种配置数据。其中一些数据本身需要(例如用户货币),但其他数据用于确定应该使用哪个服务实现。甚至其他数据也被用作实现本身;意味着我通过 HTTP GET 获得一个对象的实例(实现特定的接口IMyInterface),并希望将此实例注册为IMyInterface.

然后应该将此配置数据(或相应的服务)添加回我的IServiceProvider,以便可以将它们注入到稍后将显示的页面中。这就是我的问题所在:

IServiceProvider在已经构建之后,有没有办法在运行时稍后添加服务实现?请记住,如果可能的话,我只想使用来自Microsoft.Extensions.DependencyInjection( IServiceCollection,IServiceProvider等) 的东西,而不是第三方容器(我知道这适用于例如 DryIoC)。如果我能够添加IOptionsIServiceProvider稍后的执行中,部分帮助是有帮助的,但我更有可能需要添加服务实现。

4

2 回答 2

1

我认为这不可能直接,但你可以做这样的事情

public void ConfigureServices(IServiceCollection services)
{
    // Register the all required implementations using their implementation name
    services.AddScoped<MyService1>();
    services.AddScoped<MyService2>();
    services.AddScoped<MyService3>();

    // Decide on the required implementation at runtime and return the correct one
    services.AddScoped<IMyService>(context => 
    {
        //logic here for deciding on the implementation
        if (useService1)
        {
            return context.GetRequiredService<MyService1>();
        }
        else if (userService2)
        {
            return context.GetRequiredService<MyService2>();
        }
        
        return context.GetRequiredService<MyService3>();
    });
}
于 2021-02-11T10:06:24.143 回答
0

IServiceCollection提供了一种扩展方法,允许工厂方法创建您的服务。所以你可以在你的方法中添加一个类似这样的ConfigureServices方法。

services.AddTransient<IMyService>((serviceProvider) =>
{
   // You can get services you need to decide what implementation to use like so
   var someDecidingService = serviceProvider.GetService<ISomeOtherService>();

   // you can use whatever logic you need to decide what implementation to use
   if (someDecidingService.UseImplementationA())
   {
      return new ImplementationA();
   }
   else
   {
     return new ImplementationB();
   }
});

根据您的逻辑,尽管将工厂类添加到您的容器可能更有意义,它可以封装用于决定使用哪个服务实现的逻辑。

于 2021-02-11T10:03:08.480 回答