我想创建一个新的DI范围来更改服务注册,我有几个需要的用例,例如,对于ICurrentPrincipalAccessor
,ThreadPrincipalAccessor
和{{1}有两个实现},我以前在控制台中使用HttpContextPrincipalAccessor
,在ASP.NET中使用ThreadPrincipalAccesor
。在注入HttpContextPrincipalAccesor
的库类中,直到需要从ASP.NET应用程序中的托管服务访问主体时,我才没有遇到问题。
这是我已注册的ASP.NET应用程序:
ICurrentPrincipalAccesor
然后在托管服务中,我创建一个子范围:
services.AddTransient<ICurrentPrincipalAccessor, HttpContextPrincipalAccesor>();
using (var scope = _serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetService<MyGreatServiceWhatDoSomethingWithPrincipal>();
service.DoSomething();
}
具有MyGreatServiceWhatDoSomethingWithPrincipal
依赖性,并且注入了ICurrentPrincipalAccessor
,但是在这种情况下,从托管服务调用,我想注入HttpContextPrincipalAccesor
,我想这样做像这样:
ThreadPrincipalAccessor
是的,我可以访问using (var scope = _serviceProvider.CreateScope(collectionService => {
// Define here the new scope service configurations
collectionService.AddTransient<ICurrentPrincipalAccessor, ThreadPrincipalAccesor>();
}))
{
var service = scope.ServiceProvider.GetService<MyGreatServiceWhatDoSomethingWithPrincipal>();
service.DoSomething();
}
,如果对HttpContext.User
的访问权限为空,那么好!但在更多的用例中,我想更改子作用域的服务配置。
你能帮我吗?
另一方面,我将Autofac用作IoC容器,也许我可以对Autofac做一些特定的事情。
答案 0 :(得分:1)
好吧,我自己问题中的最后一个音符为我打开了一条新路。
我一直在查看ServiceProvider
代码,但没有发现这样做的可能性。但是,我一直在搜索Autofac documentation,并且看到了可能。
我已经创建了自己的服务范围工厂:
public interface ISinaiServiceScopeFactory
{
IServiceScope CreateScope(Action<IServiceCollection> configureServices);
}
public class SinaiServiceScopeFactory : ISinaiServiceScopeFactory
{
private readonly ILifetimeScope _lifetimeScope;
public SinaiServiceScopeFactory(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}
public IServiceScope CreateScope(Action<IServiceCollection> configureServices)
{
var sc = new SinaiServiceCollection();
configureServices.Invoke(sc);
var scope = this._lifetimeScope.BeginLifetimeScope(container =>
{
container.Populate(sc);
});
return new AutofacServiceScope(scope); // That is internal in Autofac, I have created a copy :P
}
}
AutofacServiceScope sourcecode
以及服务提供商的扩展方法:
public static class SinaiServiceProviderExtensions
{
public static IServiceScope CreateScope(this IServiceProvider serviceProvider,
Action<IServiceCollection> configureServices)
{
var serviceScopeFactory = serviceProvider.GetService<ISinaiServiceScopeFactory>();
return serviceScopeFactory.CreateScope(configureServices);
}
}
测试正常:
public class SinaiServiceScopeFactoryTests
{
interface I1 {}
class C1 : I1 {}
class C2 : I1 {}
[Fact]
public void Should_Override_Services_On_New_Scope()
{
var sc = new SinaiServiceCollection();
sc.AddTransient<I1, C1>();
sc.AddTransient<ISinaiServiceScopeFactory, SinaiServiceScopeFactory>();
var spf = new AutofacServiceProviderFactory();
var builder = spf.CreateBuilder(sc);
var sp = spf.CreateServiceProvider(builder);
var service1 = sp.GetService<I1>();
using (var scope = sp.CreateScope(sc => sc.AddTransient<I1, C2>()))
{
var service2 = scope.ServiceProvider.GetService<I1>();
Assert.Equal(typeof(C1), service1.GetType());
Assert.Equal(typeof(C2), service2.GetType());
}
}
}