给定一个ContainerBuilder,我可以注册一个缺少的依赖处理程序吗? [英] Given a ContainerBuilder, can I register a missing dependency handler?
问题描述
我正在尝试制作一种具有以下签名的方法:
I am trying to make a method with the following signature:
void Chain(ContainerBuilder builder, IServiceProvider fallbackServiceProvider)
{
// ...
}
想法是 Chain
可以按以下方式使用:
The idea is that Chain
can be used as follows:
IServiceProvider fallbackProvider = someExternalProvider;
var builder = new ContainerBuilder();
// Custom registration might happen before and/or after the call to Chain
builder.Register<MyCustomService>().As<IMyCustomService>();
builder.Register<MyExternalServiceReplacement>.As<IExternalService>();
Chain(builder, someExternalProvider);
IContainer container = builder.Build();
// customService should be a MyCustomService
var customService = container.Resolve<IMyCustomService>();
// replacedService should be overridden by MyExternalServiceReplacement
// even though an IExternalService also exists in someExternalProvider
var replacedService = container.Resolve<IExternalService>();
// nonReplacedService should come from someExternalProvider since
// no IExternalService2 was registered with the ContainerBuilder
var nonReplacedService = container.Resolve<IExternalService2>();
理想情况下,我可以向ContainerBuilder注册某种缺少的依赖处理程序.
Ideally there would be some type of missing dependency handler that I could register with the ContainerBuilder.
或者,我可能可以通过某种方式来注册一个组件,该组件可以拦截对 Resolve *
, TryResolve *
等的每次调用.需要拦截依赖项解析以进行构造函数注入.
Alternatively, I could probably get by with some way to register a component that could intercept every call to Resolve*
, TryResolve*
, etc... This would also need to intercept the dependency resolution for constructor injection.
不幸的是,无法查询IServiceProvider来获取它提供的每个服务.我只能调用 fallbackServicProvider
的 object IServiceProvider.GetService(Type serviceType)
方法.
Unfortunately, there is no way to query the IServiceProvider to get every service it provides. I can only call into the object IServiceProvider.GetService(Type serviceType)
method of the fallbackServicProvider
.
推荐答案
您需要一个自定义的 IRegistrationSource
实现:当容器需要提供服务时,它将查询已注册的注册源以获取任何可用的实现.
You need a custom IRegistrationSource
implementation: when the container needs to provide a service, it queries the registered registration sources to get any available implementations.
因此,在注册源中,您可以要求您的 IServiceProvider
为给定类型提供后备实现.
So inside the registeration source you can ask your IServiceProvider
to give you a fallback implementation for a given type.
这是一篇很好的文章,介绍了Autofac中的整个注册来源:声明性Autofac 2中的上下文适配器
Here is a good article intoroducing the whole registration source in Autofac: Declarative Context Adapters in Autofac 2
基于这一点,我整理了一个原型 IRegistrationSource
实现(因此尚未经过全面测试,也没有生产准备就绪,但它已与您的示例场景一起使用),这是什么?您可以基于:
Based on that I've knocked together a prototype IRegistrationSource
implementation (so it is not fully tested nor production ready, but it was working with your sample scenario) what you can build on:
public class MyRegistrationSource : IRegistrationSource
{
private readonly IServiceProvider serviceProvider;
public MyRegistrationSource(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
// there are other registration exists in the container
if (registrationAccessor(service).Any())
return Enumerable.Empty<IComponentRegistration>();
var swt = service as IServiceWithType;
if (swt == null)
return Enumerable.Empty<IComponentRegistration>();
// try to get an instance from the IServiceProvider
var instance = serviceProvider.GetService(swt.ServiceType);
if (instance == null)
return Enumerable.Empty<IComponentRegistration>();
// register the instance in the container
return new[]
{
RegistrationBuilder.ForDelegate(swt.ServiceType,
(c, p) => instance)
.CreateRegistration()
};
}
public bool IsAdapterForIndividualComponents { get { return false; } }
}
您可以像这样使用它:
var builder = new ContainerBuilder();
// Custom registration might happen before and/or after the call to Chain
builder.RegisterType<MyCustomService>().As<IMyCustomService>();
builder.RegisterType<MyExternalServiceReplacement>().As<IExternalService>();
//Chain(builder, someExternalProvider);
builder.RegisterSource(new MyRegistrationSource(new ServiceProvider()));
IContainer container = builder.Build();
这篇关于给定一个ContainerBuilder,我可以注册一个缺少的依赖处理程序吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!