【发布时间】: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