给定一个ContainerBuilder,我可以注册一个缺少的依赖处理程序吗? [英] Given a ContainerBuilder, can I register a missing dependency handler?

查看:45
本文介绍了给定一个ContainerBuilder,我可以注册一个缺少的依赖处理程序吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作一种具有以下签名的方法:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆