我试图弄清楚如何使用Autofac 3.5.2在运行时从容器中按名称解析类型。我的用例是每个业务合作伙伴都有一个自定义回调策略,需要通过容器注入不同类型,但我不知道在运行时我需要哪个合作伙伴策略。所以:
class PartnerAStrategy(ISomeType aSomeType, ILog someLog) : ICallbackStrategy {}
和
class PartnerBStrategy(ISomeOtherType aSomethingElse, IShoe aSneaker) : ICallbackStrategy {}
我知道在使用它之后我需要哪种策略
class PartnerSSOController {
void PartnerSSOController(IPartnerFactory aFactory){
thePartnerFactory = aFactory;
}
void DoLogin(){
// 'PartnerB'
string aPartner = GetPartnerNameFromContext();
//get from container, not reflection
ICallbackStratgey aStrategy = thePartnerFactory.ResolveCallback(aPartner);
aStratgey.Execute();
}
}
class PartnerFactory : IPartnerFactory{
ICallbackStratgey ResolveCallback(string aPartnerName){
string aCallbackTypeINeed = string.format("SSO.Strategies.{0}Strategy", aPartnerName);
// need container to resolve here
}
}
假设所有内容都已成功注册到容器,我将如何在Autofac SSO模块中注册回调?我试过这个:
aBuilder.Register(aComponentContext => {
IPartnerFactory aFactory = aComponentContext.Resolve<IPartnerFactory>();
string aTypeName = String.Format("SSO.Strategies.{0}Strategy", /** how to access partner name here? **/);
Type aTypeToReturn = Type.GetType(aTypeName, false, true) ?? typeof(DefaultCallbackStrategy);
return aComponentContext.Resolve(aTypeToReturn);
})
.As<ICallbackStrategy>()
但正如您所看到的,我无法弄清楚如何在回调期间使合作伙伴或类型名称可用。 我希望避免专门注册每个合作伙伴的回调并提供一个密钥名称(如果可能的话),因为我喜欢在程序集中扫描模块中的类型:
aBuilder.RegisterAssemblyTypes(typeof(CallbackBase).Assembly)
.Where(aType => typeof(ICallbackStrategy).IsAssignableFrom(aType))
.AsImplementedInterfaces()
.AsSelf();
答案 0 :(得分:0)
我认为您正在寻找的是Autofac元数据支持,特别是可以与程序集扫描一起使用的属性元数据。这里有大量的文档和示例:http://autofac.readthedocs.org/en/latest/advanced/metadata.html
答案 1 :(得分:0)
我认为Travis使用MetaData的方法可能有用,但这就是我今天解决这个问题的方法。
我的真实场景使用SSOPartner
对象而不是我在原始问题中使用的字符串PartnerName
,所以请注意这一点。
首先,我通过查找实现ICallbackStrategy
的每种类型来注册SSO程序集中的所有自定义伙伴策略。 CallbackBase
是目标程序集中的类型:
aBuilder.RegisterAssemblyTypes(typeof(CallbackBase).Assembly)
.Where(aType => typeof(ICallbackStrategy).IsAssignableFrom(aType))
.AsImplementedInterfaces()
.AsSelf();
然后我在作品根目录中注册了Func<ISSOPartner, ICallbackStrategy>
:
aBuilder.Register<Func<ISSOPartner, ICallbackStrategy>>((aComponentContext, aPartner) => {
IComponentContext aResolvedContext = aComponentContext.Resolve<IComponentContext>();
return aSSOPartner => {
string aType = String.Format("SSO.Strategies.{0}Strategy", aSSOPartner.Name);
Type aCallbackType = Type.GetType(aType, false, true);
return (ICallbackStrategy)aResolvedContext.Resolve(aCallbackType, new NamedParameter("anSSOPartner", aSSOPartner));
};
});
如您所见,每个策略都将构造函数中的SSOPartner
对象作为命名参数。这有助于演示如何使用混合类型从容器中解析对象,其中一些类型已在容器中注册,而另一些则未在容器中注册。
让我更新我原来的例子:
class PartnerAStrategy(ISSOPartner anSSOPartner) : ICallbackStrategy {}
和
class PartnerBStrategy(ISSOPartner anSSOPartner, IShoe aSneaker) : ICallbackStrategy {}
aResolvedContext.Resolve
会在运行时通过查看容器找到PartnerB的IShoe
。容器不了解ISSOPartner
。
最后,我依赖于我需要使用它的位置Func<ISSOPartner, ICallbackStrategy>
并调用它来调用我在组合根处定义的lambda:
public class SSOController : Controller {
private readonly Func<ISSOPartner, ICallbackStrategy> theCallbackResolverFunc;
public SSOController(Func<ISSOPartner, ICallbackStrategy> aCallbackResolverFunc){
theCallbackResolverFunc=aCallbackResolverFunc;
}
public async Task<ActionResult> DoSSO() {
SSOPartner anSSOPartner = GetThePartner();
ICallbackStrategy aCallback = theCallbackResolverFunc.Invoke(anSSOPartner);
var aReturn = await aCallback.Execute();
...
}
}
SSOController
传递了对我在合成根目录中注册的Func
的引用。我执行该Func并传入SSOPartner
,其中有一个名为Name
的属性,我用它来解析ICallbackStrategy
类型。