【Autofac笔记】一个服务多个实现
当一个服务注册多个实现时,如何区分?如果我们一个服务只有一个实现类,直接使用As()
即可,但是如果一个服务有多个实现类,如何获取实现类
获取全部实现类
解析时直接使用IEnumerable<服务类型>
类型的参数,如下
注册:
builder.RegisterType<Cat>().As<IAnimal>();
builder.RegisterType<Dog>().As<IAnimal>();
builder.RegisterType<Panda>().As<IAnimal>();
解析:
public IActionResult Index([FromServices] IEnumerable<IAnimal> animals)
{
return View();
}
按键
获取指定实现类
在注册时进一步按键标识,解析时使用键解析。键可以时一个名字、枚举、Type...
被注入的类在注册时要调用WithAttributeFiltering()
注册:
builder.RegisterType<AnimalHome>().WithAttributeFiltering();
builder.RegisterType<Cat>().Keyed<IAnimal>("cat");//按名称
builder.RegisterType<Dog>().Keyed<IAnimal>("dog");
builder.RegisterType<Panda>().Keyed<IAnimal>(typeof(Panda));//按Type
构造函数注入:
public AnimalHome([KeyFilter("dog")] IAnimal animals)
{
}
IIndex索引注入
解析组件可以使用IIndex<K,V>
作为参数的构造函数从基于键的服务中选择需要的实现。
它的好处是动态的选择需要解析的服务,而不是在构造函数中就决定使用哪个键
注册:
builder.RegisterType<AnimalFactory>();
解析:
public class AnimalFactory
{
private readonly IIndex<Type, IAnimal> _lookup = null;
public AnimalFactory(IIndex<Type, IAnimal> lookup)
{
this._lookup = lookup;
}
public IAnimal Create(Type handlerType)
{
return this._lookup[handlerType];
}
}
扩展KeyFilter
[KeyFilter]
是通过继承ParameterFilterAttribute
来实现功能,我们可以自己写一个类继承ParameterFilterAttribute
,可以更灵活解析:
public sealed class DependencyDBAttribute : ParameterFilterAttribute
{
public DependencyDBAttribute(string serviceKey, bool readOnly)
{
this.ServiceKey = serviceKey;
this.ReadOnly = readOnly;
}
public string ServiceKey { get; }
public bool ReadOnly { get; set; }
public override object ResolveParameter(ParameterInfo parameter, IComponentContext context)
{
if (string.IsNullOrWhiteSpace(this.ServiceKey))
return this.ReadOnly
? context.ResolveKeyed("_slave", parameter.ParameterType, new NamedParameter("readOnly", true))
: context.Resolve(parameter.ParameterType);
return this.ReadOnly
? context.ResolveKeyed($"{this.ServiceKey}_slave", parameter.ParameterType, new NamedParameter("readOnly", true))
: context.ResolveKeyed(this.ServiceKey, parameter.ParameterType);
}
}
注入:
public class CommonService
{
public CommonService([DependencyDBAttribute("master", true)]IDB db)
{
}
}