在ASP.NET Core中的控制器中注入接口的特定实现

时间:2018-01-17 18:43:44

标签: c# asp.net-core autofac

我正在开发一个基于ASP.NET Core的Web应用程序,我使用Autofac进行依赖注入。

我的界面为ICacheProvider,此界面有3个具体实现 - OrderCacheProviderProductsCacheProviderCustomerCacheProvider。不同缓存提供商的基础架构和逻辑是不同的。它们的注册如下:

builder.RegisterType<CustomerCacheProvider>()
            .Keyed<ICacheProvider>(CacheType.Customer);
builder.RegisterType<OrderCacheProvider>()
            .Keyed<ICacheProvider>(CacheType.Order);
builder.RegisterType<ProductCacheProvider>()
            .Keyed<ICacheProvider>(CacheType.Product);

现在我有3个控制器 - OrdersControllerProductsControllerCustomerController。每个控制器都期望以下方式ICacheProvider

public class OrdersController: BaseController {
    private readonly ICacheProvider _cacheProvider;
    public OrdersController(ICacheProvider cacheProvider) {
         _cacheProvider = cacheProvider;
    }
}

现在我的问题是如何在OrderCacheProvider中注入注入OrdersControllerCustomerCacheProvderCustomersControllerProductsCacheProvider同样如此?

1 个答案:

答案 0 :(得分:1)

您可以在注册控制器时使用WithParameter方法指定应使用哪个ICacheProvider

builder.RegisterType<OrdersController>()
        .WithParameter(ResolvedParameter.ForKeyed<ICacheProvider>(CacheType.Order));

另一种选择是使用KeyFilter属性

public class OrdersController
{
    public OrdersController([KeyFilter(CacheType.Order)]ICacheProvider cacheProvider)
    { }
}

我更喜欢第一个解决方案,而不是那个看起来更的解决方案,您的组件只需再请求ICacheProvider

另一种解决方案是创建一个自定义模块,该模块将根据约定为每个控制器添加参数。

    protected override void AttachToComponentRegistration(
        IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        base.AttachToComponentRegistration(componentRegistry, registration);

        if (registration.Activator.LimitType.IsSubclassOf(typeof(BaseController)))
        {
            String controllerName = registration.Activator.LimitType.Name;
            controllerName = controllerName.Substring(0, controllerName.Length - 10);
            if (Enum.TryParse<CacheType>(controllerName, out CacheType cacheType))
            {
                registration.Preparing += (sender, e) =>
                {
                    e.Parameters = new Parameter[]
                                   {
                                      ResolvedParameter.ForKeyed<ICacheProvider>(cacheType)
                                   }
                                   .Concat(e.Parameters);
                };
            }
            else
            {
                // throw, use default cache, do nothing, etc.
                throw new Exception($"No cache found for controller {controllerName}");
            }
        }
    }
}

这是更多代码,但您不必为每个控制器注册使用WithParameter,如果您有很多控制器,它可能会很棒。您仍然需要注册模块:

builder.RegisterModule<CacheProviderModule>();
相关问题