【问题标题】:Updating MVC4 & WebAPI to MVC5 & WebAPI 2 Broken MEF Implementation将 MVC4 和 WebAPI 更新为 MVC5 和 WebAPI 2 损坏的 MEF 实现
【发布时间】:2014-08-11 00:46:11
【问题描述】:

我刚刚将我的 MVC4 应用更新为 MVC5,由于某种原因,这似乎同时完全破坏了我的 MEF 实现。

我的解决方案中的以下代码 sn-ps 已经顺利运行了一年多,我并不完全清楚解决方案是什么。

我有两个解决方案,一个 MVC5 网站和一个 MVC WebAPI 2 解决方案。

我在网站上看到的错误是:

"Currently composing another batch in this ComposablePartExportProvider. Only one batch can be composed at a time."

在 WebAPI 解决方案上,控制器类中的 [Import] 标记字段均未填充并生成“对象未设置为对象实例”。考虑到相同的代码已经运行了一年多没有问题,所有这些都非常令人困惑。

通过检查容器部件,所有预期和需要的部件都存在。

MVC5 网站 Mef 配置

public static class MefConfig
{
    public static void RegisterMef()
    {
        var container = ConfigureContainer();
        ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
        GlobalConfiguration.Configuration.DependencyResolver = new MefControllerFactory(container);
    }

    private static CompositionContainer ConfigureContainer()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
        catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(MoodConfig.AppBaseDirectory, @"bin\plugins")));

        var container = new CompositionContainer(catalog, true);
        return container;
    }

WebApi 2 Mef 配置

public static class MefConfig
{
    public static void RegisterMef()
    {
        var container = ConfigureContainer();
        ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
        GlobalConfiguration.Configuration.DependencyResolver = new MefControllerFactory(container);
    }

    private static CompositionContainer ConfigureContainer()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
        catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(ConfigHelper.AppBaseDirectory, @"bin\plugins")));
        var container = new CompositionContainer(catalog, true);
        return container;
    }
}

MefControllerFactory

public class MefControllerFactory : DefaultControllerFactory, System.Web.Http.Dependencies.IDependencyResolver
{
    private readonly CompositionContainer _compositionContainer;

    private bool _disposed;

    public MefControllerFactory(CompositionContainer compositionContainer)
    {
        _compositionContainer = compositionContainer;
    }

    public IDependencyScope BeginScope()
    {
        return this;
    }

    public object GetService(Type serviceType)
    {
        var export = _compositionContainer.GetExports(serviceType, null, string.Empty).SingleOrDefault();

        return null != export ? export.Value : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        var exports = _compositionContainer.GetExports(serviceType, null, string.Empty);
        return exports.Select(export => export.Value).ToList();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            var baseMessage = "Not Found, controllerType is null";
            if (requestContext != null)
            {
                throw new HttpException(404, string.Format("{0} RequestedUrl: {1}", baseMessage, requestContext.HttpContext.Request.Url));
            }

            throw new HttpException(404, baseMessage);
        }

        var export = _compositionContainer.GetExports(controllerType, null, string.Empty).SingleOrDefault();

        IController result;

        if (null != export)
        {
            result = export.Value as IController;
        }
        else
        {
            result = base.GetControllerInstance(requestContext, controllerType);
            _compositionContainer.ComposeParts(result);
        }

        return result;
    }

    private void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
            }
        }

        _disposed = true;
    }
}

两种解决方案中的所有控制器都标记如下:

[Export(typeof(MyController)), PartCreationPolicy(CreationPolicy.NonShared)]

我发现真正令人困惑的是,相同的代码已经运行了很长时间而没有出现问题,而且由于我没有更改 .NET 版本 (4.5),所以它应该运行相同的 MEF 代码。

我正在做的事情显然存在问题,我已经读过从使用 ComposeParts 方法更改为使用 SatisfyImportsOnce 方法可以解决问题。当我更改代码以使用此方法时,我不再收到 batch composing 错误,但我的 [Import] 属性在 API 控制器上仍然为空,尽管部件位于容器中。

我真的不清楚为什么在升级新版本的 MVC 和 WebAPI 后首先开始发生这种情况,我也不清楚最终的解决方案是什么。

我的实现主要基于此:

http://kennytordeur.blogspot.co.uk/2012/08/mef-in-aspnet-mvc-4-and-webapi.html

有没有人看到类似的并解决了这个问题?你的情况有什么解决办法?

【问题讨论】:

  • 自从提出这个问题以来,我已经尝试了各种解决方案,但它仍然被彻底破坏。看起来 WebAPI2 在这方面的工作方式截然不同,任何人提供的任何信息都会有所帮助。

标签: c# asp.net-mvc asp.net-web-api mef


【解决方案1】:

我遇到了同样的问题,我能够在构建插件项目的“扩展”文件夹中导入 dll,我的 web-api 是导入 angularjs 路由的简单方法,因此 dll 中的 angularjs 控制器工作,但我尝试了所有关于如何使用 MEF 导入 dll 中定义的 ApiControllers 的教程,但由于某些晦涩的原因,没有任何效果。我不知道这对您来说是否是一个可行的解决方案,但是将 dll 从“扩展”文件夹移动到主项目的 bin 文件夹使 ApiControllers 自动被发现并且一切都像我不需要导入的魅力一样工作带有 MEF 的控制器(我仍然使用 MEF 导入 .js 和 .html,但仅此而已),看起来 MVC 实现了自己的方式来发现运行环境中的控制器。

【讨论】:

  • 看起来很奇怪不是吗。感觉像一门黑色艺术。
  • 看来我今天要再次尝试升级。祝我好运!哈!
猜你喜欢
  • 1970-01-01
  • 2017-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
相关资源
最近更新 更多