C# 稍后在执行中更改服务实现(在Microsoft.Extensions.DependencyInjection中)
我有一个用例(带有登录的应用程序,以及在此之后具有不同功能的各种页面可供浏览),在该用例中,我在C# 稍后在执行中更改服务实现(在Microsoft.Extensions.DependencyInjection中),c#,.net,dependency-injection,.net-standard,microsoft.extensions.hosting,C#,.net,Dependency Injection,.net Standard,Microsoft.extensions.hosting,我有一个用例(带有登录的应用程序,以及在此之后具有不同功能的各种页面可供浏览),在该用例中,我在ConfigureServices方法中注册了我的大部分服务(通常会这样做),因此在实际(UI)执行我的程序之前 然而,我有一些服务,我只注册为傻瓜(甚至根本没有),因为这些服务应该在我登录到web服务后设置。在此登录过程中,不仅会检查用户是否有效,还会在用户验证后获取各种配置数据。其中一些数据本身需要(例如,用户货币),但其他数据用于确定应使用哪个服务实现。甚至其他数据也被用作实现本身;意味着我通过
ConfigureServices
方法中注册了我的大部分服务(通常会这样做),因此在实际(UI)执行我的程序之前
然而,我有一些服务,我只注册为傻瓜(甚至根本没有),因为这些服务应该在我登录到web服务后设置。在此登录过程中,不仅会检查用户是否有效,还会在用户验证后获取各种配置数据。其中一些数据本身需要(例如,用户货币),但其他数据用于确定应使用哪个服务实现。甚至其他数据也被用作实现本身;意味着我通过HTTP get获取对象的实例(实现特定接口IMyInterface
),并希望将此实例注册为IMyInterface
的实现
然后应将这些配置数据(或相应的服务)添加回myIServiceProvider
,以便将它们注入稍后显示的页面中。这就是我的问题所在:
在构建了
IServiceProvider
之后,有没有办法在运行时添加服务实现?请记住,如果可能的话,我只想使用Microsoft.Extensions.DependencyInjection
(IServiceCollection
,IServiceProvider
)中的内容而且没有第三方容器(我知道这在DryIoC中就是一个例子)。如果我能够在以后的执行中将IOptions
添加到IServiceProvider
中,那么会有部分帮助,但我更可能需要添加服务实现。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();
}
});
services.AddTransient((serviceProvider)=>
{
//您可以获得您需要的服务来决定使用什么样的实现
var somedecisionservice=serviceProvider.GetService();
//您可以使用您需要的任何逻辑来决定使用什么实现
if(someDecisingService.UseImplementationA())
{
返回新的实现a();
}
其他的
{
返回新的实现b();
}
});
根据您的逻辑,在容器中添加工厂类可能更有意义,因为它可以封装用于决定使用哪个服务实现的逻辑。我认为不可能直接实现,但您可以这样做
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>();
});
}
public void配置服务(IServiceCollection服务)
{
//使用实现名称注册所有必需的实现
services.addScope();
services.addScope();
services.addScope();
//在运行时决定所需的实现并返回正确的实现
services.AddScoped(上下文=>
{
//这里是决定实现的逻辑
如果(使用服务1)
{
返回context.GetRequiredService();
}
else if(userService2)
{
返回context.GetRequiredService();
}
返回context.GetRequiredService();
});
}
更好的办法是从提供者那里获得服务,如果构造函数很复杂,使用new可能会变得很麻烦,因为存在许多依赖项