我正在开发基于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也是一样吗?

最佳答案

注册控制器时,可以使用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>();

08-25 20:33