c# - 给定一个 ContainerBuilder,我可以注册一个缺失的依赖处理程序吗?

标签 c# autofac

我正在尝试创建一个具有以下签名的方法:

void Chain(ContainerBuilder builder, IServiceProvider fallbackServiceProvider)
{
   // ...
}

这个想法是Chain可以按如下方式使用:

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 注册某种类型的缺失依赖项处理程序。

或者,我可能会通过某种方式来注册一个组件,该组件可以拦截对 Resolve*TryResolve* 等的每次调用...这也需要拦截构造函数注入(inject)的依赖解析。

遗憾的是,无法查询 IServiceProvider 以获取它提供的每项服务。我只能调用 fallbackServicProviderobject IServiceProvider.GetService(Type serviceType) 方法。

最佳答案

您需要一个自定义的IRegistrationSource 实现:当容器需要提供服务时,它会查询已注册的注册源以获取任何可用的实现。

因此在注册源中,您可以要求您的 IServiceProvider 为您提供给定类型的回退实现。

这里有一篇很好的文章介绍了 Autofac 中的整个注册源:Declarative Context Adapters in Autofac 2

基于此,我拼凑了一个原型(prototype) IRegistrationSource 实现(因此它没有经过全面测试,也没有准备好生产,但它可以与您的示例场景一起使用)什么你可以建立在:

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();

关于c# - 给定一个 ContainerBuilder,我可以注册一个缺失的依赖处理程序吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22335609/

相关文章:

autofac - 通过 IAsyncInterceptor 使用 Autofac 接口(interface)拦截

C# ASP.Net Core 与 Autofac 集成时面临的问题

c# - Autofac - 在运行时解析 IEnumerable 通用接口(interface)

c# - 反转数组数组

c# - 如何使用 ExecuteSqlInterpolatedAsync() 在 EF Core 3.0 中使用输出参数

c# - 如何判断两个多边形是否相交?

c# - 无法将解析的对象转换为通用抽象 autofac C#

c# - Autofac - 注册多个装饰器

c# - 将列表拆分为 block - C#

c# - 禁用并行构建