【问题标题】:Custom Service Locator with MEF and IOC container from galasoft来自 Galasoft 的带有 MEF 和 IOC 容器的自定义服务定位器
【发布时间】:2013-12-23 06:50:13
【问题描述】:

我有一个要求,我必须在我的应用程序中支持两种类型的容器。因此,我创建了一个自定义 ServiceLocator,它为 2 种类型的容器提供服务,即

  1. SimpleIoc (Galasoft)

  2. MefServiceLocatorAdapter

因此,我创建了一个通用服务定位器类,即

public class CommonServiceLocator : ServiceLocatorImplBase
{
    private IServiceLocator _iocContainer, _mefContainer;

    public CommonServiceLocator(IServiceLocator iocLocator, IServiceLocator mefLocator)
    {
        _iocContainer = iocLocator;
        _mefContainer = mefLocator;
    }

    protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
    {

        IEnumerable<object> services;
        try
        {
            services = _iocContainer.GetAllInstances(serviceType);
        }
        catch (Exception)
        {
            //Current assumption is that if IocContainer doesn't contain an instance then
            //it should look for MefContainer for values
            services = _mefContainer.GetAllInstances(serviceType);
        }
        return services;
    }

    protected override object DoGetInstance(Type serviceType, string key)
    {
        object service;
        try
        {
            service = _iocContainer.GetInstance(serviceType, key);
        }
        catch (Exception)
        {
            //Current assumption is that if IocContainer doesn't contain an instance then
            //it should look for MefContainer for values
            service = _mefContainer.GetInstance(serviceType, key); //<== This fails to get an instance
        }
        return service;
    }

    public override object GetInstance(Type serviceType, string key)
    {
        return DoGetInstance(serviceType, key);
    }

    public override object GetInstance(Type serviceType)
    {
        return GetInstance(serviceType, null);
    }
}

现在,问题是当我尝试使用 GetInstance() 方法通过 IOC 容器获取类实例时,它工作正常。但是,通过 MefContainer 获取类实例会引发一些错误(“System.Core.dll 中发生了“System.InvalidOperationException”类型的第一次机会异常”)。我创建了一个测试类来测试这个场景:

public class ServiceLocatorTest
{
    public void CommonServiceLocatorInstanceTest()
    {
        var serviceLocator = new SimpleIoc();
        serviceLocator.Register<GalaSoftIocData>();

        AggregateCatalog catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(MefCompositionAddin).Assembly));
        CompositionContainer compContainer = new CompositionContainer(catalog);

        CompositionBatch batch = new CompositionBatch();

        batch.AddPart(AttributedModelServices.CreatePart(new MefCompositionAddin()));

        compContainer.Compose(batch);

        var vl = compContainer.GetExportedValue<MefCompositionAddin>(); // <== This gives instance correctly
        var mefserviceLocator = new MefServiceLocatorAdapter(compContainer);
        var commonServiceLocator = new CommonServiceLocator(serviceLocator, mefserviceLocator);
        var galaSoftData = commonServiceLocator.GetInstance(typeof(GalaSoftIocData));
        var mefData = commonServiceLocator.GetInstance(typeof(MefCompositionAddin));
    }
}

[Export]
class MefCompositionAddin
{

    public string MyData { get { return "Mef's Data composed"; } }

    [Import]
    public MefCompositionAddin MyObj { get; set; }
}

class MefCompositionData
{
    [Import]
    public MefCompositionAddin MyAddin { get; set; }
}

class GalaSoftIocData
{
    public string MyData { get { return "Galasoft's Data composed"; } }
}

如果我错过了什么,请告诉我。以及可能的原因是什么。提前感谢大家的帮助。

【问题讨论】:

  • 您能否提供有关此异常的更多详细信息,例如:堆栈跟踪(如果它很长,则几个顶级调用就足够了)?它有内部异常吗?
  • System.InvalidOperationException 发生 HResult=-2146233079 消息=序列包含多个元素 Source=System.Core StackTrace:在 Microsoft 的 System.Linq.Enumerable.Single[TSource](IEnumerable`1 源) .Practices.Prism.MefExtensions.MefServiceLocatorAdapter.DoGetInstance(Type serviceType, String key) 在 c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft 中的 Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key)。 Practices.ServiceLocation\ServiceLocatorImplBase.cs:第 49 行 InnerException:
  • 另外,没有InnerException

标签: c# .net prism mef


【解决方案1】:

我相信您正在使用 Prism 库中提供的 MefServiceLocatorAdapter。这是它的 DoGetInstance 方法的代码:

protected override object DoGetInstance(Type serviceType, string key)
{
    IEnumerable<Lazy<object, object>> exports = this.compositionContainer.GetExports(serviceType, null, key);
    if ((exports != null) && (exports.Count() > 0))
    {
        // If there is more than one value, this will throw an InvalidOperationException, 
        // which will be wrapped by the base class as an ActivationException.
        return exports.Single().Value;
    }

    throw new ActivationException(
        this.FormatActivationExceptionMessage(new CompositionException("Export not found"), serviceType, key));
}

正如您在评论中看到的那样,如果您为相应的服务类型和密钥导出了多个类型,则会由于 Single 方法而引发您描述的异常。

您可以查看应用程序中的导出以查看是否有某种类型映射到多个类(或多次导出同一个类)或重写该方法以使其不会引发异常(例如,使用 FirstOrDefault 而不是 Single。)

注意:我没有添加上述注释,它包含在库的代码中。

【讨论】:

  • 确实这才是真正的原因。我注意到以下额外的行正在创建一些额外的实例: AggregateCatalog catalog = new AggregateCatalog(); catalog.Catalogs.Add(new AssemblyCatalog(typeof(MefCompositionAddin).Assembly));
猜你喜欢
  • 2011-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 2011-11-14
  • 1970-01-01
  • 2012-06-24
相关资源
最近更新 更多