如何使用Autofac在运行时从容器中按名称解析类型?

时间:2014-10-20 23:29:49

标签: dependency-injection autofac

我试图弄清楚如何使用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();

2 个答案:

答案 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类型。