Autofac 解决依赖关系

Autofac resolving dependencies

我对 autofac 很陌生,遇到了一些问题。 我正在使用 Web API,我的模块设置如下:

public class CormarModule : Module
{


    // Fields
    private readonly string _connectionStringName;
    private readonly connectionType _connection;

    /// <summary>
    /// Default constructor
    /// </summary>
    public CormarModule() {
        _connectionStringName =  ConfigurationManager.AppSettings["ConnectionStringName"];
        _connection = _connectionStringName.ToUpper().Contains("LIVE") ? connectionType.Live : connectionType.Test;
    }

    protected override void Load(ContainerBuilder builder)
    {

        // Singletons
        builder.RegisterType<DatabaseContext>().As<DatabaseContext>().SingleInstance();
        builder.RegisterType<UnitOfWork<DatabaseContext>>().As<IUnitOfWork>().SingleInstance();
        builder.Register(c => new OracleUnitOfWork(_connectionStringName)).As<IOracleUnitOfWork>().SingleInstance();
        builder.Register(c => new AdvancedEncryptionStandardProvider(ConfigurationManager.AppSettings["rm:key"], ConfigurationManager.AppSettings["rm:secret"])).As<IAdvancedEncryptionStandardProvider>().SingleInstance();

        // Register our services         
        builder.RegisterType<AccountService>().As<IAccountService>();
        builder.RegisterType<DeliveryInformationService>().As<IDeliveryInformationService>();
        builder.RegisterType<EmailService>().As<IEmailService>();
        builder.RegisterType<LogService>().As<ILogService>();
        builder.RegisterType<OrderService>().As<IOrderService>();
        builder.RegisterType<OrderLineService>().As<IOrderLineService>();
        builder.RegisterType<PaymentHistoryService>().As<IPaymentHistoryService>();
        builder.RegisterType<PrincipleProvider>().As<IPrincipleProvider>();
        builder.RegisterType<ProductService>().As<IProductService>();
        builder.RegisterType<RefreshTokenService>().As<IRefreshTokenService>();
        builder.RegisterType<StockService>().As<IStockService>();
        builder.Register(c => new UserStore<User>(c.Resolve<DatabaseContext>())).As<IUserStore<User>>();

        // Single instance
        builder.RegisterType<OAuthProvider>().As<OAuthProvider>();
        builder.RegisterType<LogProvider>().As<ILogProvider>();
        builder.RegisterType<RefreshTokenProvider>().As<IAuthenticationTokenProvider>();
        builder.Register(c => new SendGridProvider(c.Resolve<IUnitOfWork>(), c.Resolve<IEmailService>(), ConfigurationManager.AppSettings["SendGridApiKey"])).As<ISendGridProvider>();
        builder.Register(c => new UserProvider(_connectionStringName, c.Resolve<IUserStore<User>>(), c.Resolve<IAdvancedEncryptionStandardProvider>(), c.Resolve<ISendGridProvider>())).As<IUserProvider>();

        // Per request
        builder.RegisterType<DeliveryInformationProvider>().As<IDeliveryInformationProvider>().InstancePerRequest();
        builder.RegisterType<JournalProvider>().As<IJournalProvider>().InstancePerRequest();
        builder.RegisterType<StockProvider>().As<IStockProvider>().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies).InstancePerRequest();

        builder.Register(c => new AccountProvider(_connection, c.Resolve<IAccountService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>(), c.Resolve<IPaymentHistoryService>())).As<IAccountProvider>().InstancePerRequest();
        builder.Register(c => new ProductProvider(_connection, c.Resolve<IProductService>())).As<IProductProvider>().InstancePerRequest();
        builder.Register(c => new OrderProvider(_connection, c.Resolve<IOrderService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>())).As<IOrderProvider>().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies).InstancePerRequest();
        builder.Register(c => new OrderLineProvider(_connection, c.Resolve<IOrderLineService>(), c.Resolve<IPrincipleProvider>(), c.Resolve<IAdvancedEncryptionStandardProvider>())).As<IOrderLineProvider>().InstancePerRequest();
    }
}

我正在为不同的范围而苦苦挣扎。 在解释我的问题之前先了解一些背景知识。

每个 Provider 都有一个必需的 Service 并且每个 Controller 都有一个或多个 供应商注入。 每个 Provider 都可以有一个可选的 Provider,只有在方法调用该提供者时才应解析。

我的问题是我不知道如何设置它。 我打算将生命周期范围注入构造函数并在方法中解析所需的 Provider,但我读到这是不好的做法,而且它会创建一个新实例。我想为每个请求使用一个实例,但前提是该请求需要它。

我希望这是有道理的,我希望有人能提供帮助!

IMO,你做得很好。

你需要的是依赖Func<Provider>。当你问 Autofac a Func<> 时,它 returns 一个工厂方法,被调用而不是 .Resolve<Provider>.

有关文档,请参阅 here and here

你可以这样写:

private OptionalProvider _instance;
private Func<OptionalProvider> _providerGetter;

public OptionalProvider Prov
{
    get { return _instance ?? (_instance = _providerGetter()); }
}

public MyProvider(Func<OptionalProvider> getter)
{
    _providerGetter = getter;
}

public void MethodRequiringOptionalProvider()
{
    // just use property Prov and let Autofac handle the rest
}

另一个建议:不要直接注入 _connection 字符串参数,只需创建一个 CormarConfig class,注册到 .RegisterInstance 以存储您所有的配置选项。 这样您只需调用 RegisterType 并让 Autofac 解析所有类型参数(您摆脱了那些丑陋的 Resolve 调用)。

如果您的所有服务都继承自一个共同的祖先或实现一个共同的接口,您可以通过 Assembly ScanningAsImplementedInterfaces 注册它们。您将摆脱模块中的所有混乱。