如何使用miscrosoft 的默认 DI 机制在某个范围内注册不同的服务实现?
我的情况是这样的:
我有一个服务(我们称之为 MyJobService),它依赖于上下文值(登录的用户和其他一些信息)。我已经注册了另一个服务(UserSessionProvider),它从当前的 HttpContext 读取所需的数据。但我的初始服务也可能在后台作业中运行,其中 HttpContext 不存在,but该作业是从网络请求中解雇的。
所以我想要 UserSessionProvider 的第二个实现,其中当前用户的信息不是从 http 上下文中读取的,而是作为只读数据传递给服务实现,然后我将使用 UserSessionProvider 的这个实例作为创建的范围。
public IActionResult ControllerMethod(
[FromService] IUserSessionProvider sessionProvider, // this instance reads from http context
[FromServices] IServiceProvider sp)
{
var staticSessionProvider = new StaticDataSessionProvider( // this instance uses what you pass to the constructor
userName: sessionProvider.userName,
userData: sessionProvider.userData
);
ExecuteInBackground(()=>{
using(var scope = sp.CreateScope()){
scope.AddScoped<IUserSessionProvider>(staticSessionProvider); // can I do that?
var myJob=scope.ServiceProvider.GetService<MyJobService>(); // here 'myJob' would use the staticDataSessionProvider instance
myJob.Run();
}
});
}
如何使用miscrosoft 的默认 DI 机制在某个范围内注册不同的服务实现?
你不能。在启动过程结束时,容器被创建,并且它的注册集是固定的。这是一件好事,因为允许中途更改容器可能会导致非常不幸的后果(如本文档部分此竞争 DI 容器的)。你必须想出另一个解决方案。
例如,您可以创建一个代理实现并将其用作替代:
// Proxy implementation that dispatches to the real IUserSessionProvider
public sealed class OverwritableUserSessionProvider : IUserSessionProvider
{
// NOTE: Depends on the UserSessionProvider implementation
public OverwritableUserSessionProvider(UserSessionProvider provider)
{
this.Provider = provider;
}
// Allows replacing the dependency
public IUserSessionProvider Provider { get; set; }
// Implement IUserSessionProvider
public string UserName => this.Provider.UserName;
public UserData UserData => this.Provider.UserData;
}
该代理和真实提供者可以按如下方式注册:
// Register both the 'real' provider and the proxy.
services.AddScoped<UserSessionProvider>();
services.AddScoped<OverwritableUserSessionProvider>();
// Register the proxy as IUserSessionProvider.
services.AddScoped<IUserSessionProvider>(
sp => sp.GetRequiredService<OverwritableUserSessionProvider>());
这允许您实施您的ControllerMethod
如下:
var staticSessionProvider = new StaticDataSessionProvider(
userName: sessionProvider.userName,
userData: sessionProvider.userData);
ExecuteInBackground(() =>
{
using (var scope = sp.CreateScope())
{
// Resolve the proxy
var provider = scope.ServiceProvider
.GetRequiredService<OverwritableUserSessionProvider>();
// Replace the default dependency
provider.Provider = staticSessionProvider;
// Resolve and execute the service as usual.
var myJob = scope.ServiceProvider.GetRequiredService<MyJobService>();
myJob.Run();
}
});
TIP:将这个逻辑从控制器中提取出来并放入一个专门的类中;该逻辑是基础设施,与控制器相比有不同的关注点。
基于上述解决方案还有其他可能的解决方案和变体,但这里的技巧是始终确保容器组成相同的对象图。不要使组合对象结构动态化;不要基于运行时数据.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)