首页 > 解决方案 > 在 Autofac 中使用 RegistrationSource 自动注册

问题描述

这是我到目前为止所做的(代码简化):

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?

谢谢!

标签: dependency-injectionautofacasp.net-core-3.1

解决方案


我可能会反对传入一个ContainerBuilder.

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

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

您可以在我们的Moq 集成中看到一些很好的示例:

var reg = RegistrationBuilder.ForType(concrete)
                             .As(@interface)
                             .CreateRegistration();

另外,我认为IfNotRegistered在 a 的上下文之外使用时不会产生任何影响ContainerBuilder。您应该使用registrationAccessor注册源提供的参数来查找 aTypedService以查看它是否已经注册:

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

推荐阅读