在 Autofac 中使用 RegistrationSource 自动注册

Auto-registration with a RegistrationSource in Autofac

这是我目前所做的(代码已简化):

public class MyRegistrationSource : IRegistrationSource
{
    public MyRegistrationSource(ContainerBuilder builder /*,...*/)
    {
       // ...
       this.builder = builder;
    }

    public IEnumerable<IComponentRegistration> RegistrationsFor(
        Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        // Some checks here
        var interfaceType = serviceWithType.ServiceType;
        var implementorType = FindTheRightImplementor(interfaceType);

        if (myRegisterConditionSatisfied) 
        {
            return Register(implementorType, interfaceType);
        }

        return Empty;
    }

    private IEnumerable<IComponentRegistration> Register(Type concrete, Type @interface)
    {
        var regBuilder = builder.RegisterType(concrete).As(@interface).IfNotRegistered(@interface);
        return new[] { regBuilder.CreateRegistration() };
    }
}

然后,在启动时我正在做类似

的事情
builder.RegisterSource(
    new NonRegisteredServicesRegistrationSource(builder/*, ...*/));

以上是为了在之前没有注册的情况下才注册那些匹配的服务。我尝试在不使用 ContainerBuilder 的情况下进行注册,但无法正常工作。

这是可行的,但是在将 ContainerBuilder 实例传递给 RegistrationSource 时是否存在任何问题?

谢谢!

我可能反对传递 ContainerBuilder

您在源代码中注册的每种类型都会向 Container Builder 中的回调列表添加一个回调,该列表永远不会被清除,可能会造成内存泄漏。

我建议改为调用静态方法 RegistrationBuilder.ForType,这将为您提供一个流畅的构建器,并且应该让您随后像现在一样调用 CreateRegistration

您可以在我们的 Moq integration:

中看到一些很好的例子来说明如何做到这一点
var reg = RegistrationBuilder.ForType(concrete)
                             .As(@interface)
                             .CreateRegistration();

此外,我认为 IfNotRegisteredContainerBuilder 的上下文之外使用时不会有任何效果。你应该使用注册源提供的registrationAccessor参数来查找一个TypedService看是否已经被注册:

var isRegistered = registrationAccessor(new TypedService(@interface)).Any();