尝试将MEF与MVC控制器一起使用时,CompositionContractMismatchException

我正在开发一个更大的C#MVC 4项目,该项目分为几个程序集(Core,Domain,Backend MVC,Frontend MVC等)。 我使用MEF提供的插件架构来加载和解决大多数依赖项。 现在我也想用它来加载MVC控制器。 在几十个样本中发现了典型的场景。

但我一直得到这个YSOD:

例外情况说:

[CompositionContractMismatchException: Cannot cast the underlying exported value of type "XY.HomeController (ContractName="XY.HomeController")" to type "XY.HomeController".] System.ComponentModel.Composition.ExportServices.CastExportedValue(ICompositionElement element, Object exportedValue) +505573 System.ComponentModel.Composition.c__DisplayClass10`2.b__c() +62 System.Lazy`1.CreateValue() +14439352 System.Lazy`1.LazyInitValue() +91 XY.DependencyManagement.SomeCustomControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) in (Path)\Core\DependencyManagement\SomeCustomControllerFactory.cs:32 System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +89 System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +305 System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +87 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +12550291 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288 

自定义ControllerFactory:

  public class SomeCustomControllerFactory : DefaultControllerFactory { private readonly CompositionContainer _compositionContainer; public SomeCustomControllerFactory (CompositionContainer compositionContainer) { _compositionContainer = compositionContainer; } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { var export = _compositionContainer.GetExports(controllerType, null, null).SingleOrDefault(); IController result; if (export != null) { result = export.Value as IController; } else { result = base.GetControllerInstance(requestContext, controllerType); _compositionContainer.ComposeParts(result); } return result; } protected override Type GetControllerType(RequestContext requestContext, string controllerName) { Type controllerType = base.GetControllerType(requestContext, controllerName); // used to find objects in the container which assemblies are in a sub directory and not discovered by MVC // TODO: only create parts that are used if (controllerType == null && this._compositionContainer != null && this._compositionContainer != null) { var controllerTypes = this._compositionContainer.GetExports<Controller, IDictionary>() .Where( e => e.Value.GetType().Name.ToLowerInvariant() == controllerName.ToLowerInvariant() + ControllerNameByConvention) .Select(e => e.Value.GetType()).ToList(); switch (controllerTypes.Count) { case 0: controllerType = null; break; case 1: controllerType = controllerTypes.First(); break; case 2: throw CreateAmbiguousControllerException(requestContext.RouteData.Route, controllerName, controllerTypes); } } return controllerType; } 

和CustomDependencyResolver:

  public class CustomDependencyResolver : IDependencyResolver { private readonly CompositionContainer _container; public CustomDependencyResolver(CompositionContainer container) { _container = container; } public IDependencyScope BeginScope() { return (IDependencyScope)this; } public object GetService(Type serviceType) { var export = _container.GetExports(serviceType, null, null).SingleOrDefault(); return null != export ? export.Value : null; } public IEnumerable GetServices(Type serviceType) { var exports = _container.GetExports(serviceType, null, null); var createdObjects = new List(); if (exports.Any()) { foreach (var export in exports) { createdObjects.Add(export.Value); } } return createdObjects; } 

一切都以这种方式配置DependencyResolver.SetResolver(new CustomDependencyResolver(container)); ControllerBuilder.Current.SetControllerFactory(new SomeCustomControllerFactory(container));

附注:使用MEF2 RegistrationBuilder和带有三个AssemblyCatalog和一个DirectoryCatalog的AggregateCatalog。

如果我从主项目解决方案中提取它并创建一个新的mvc 4互联网项目解决方案并将其集成在那里,整个过程就完美无缺。 (使用一个程序集测试它,使用第二个简单的核心库。)

我已经打开了CompositionOptions.DisableSilentRejection。 并找到此资源来调试与MEF相关的错误https://blogs.msdn.com/b/dsplaisted/archive/2010/07/13/how-to-debug-and-diagnose-mef-failures.aspx?Redirected=true我删除了HomeController中的所有内容(空构造函数,没有导入等)。 MEF容器装有合适的出口。 一切都很好。

经过一整天的调试和研究,我学到了很多关于MEF的知识,但仍然遇到了同样的问题。 希望有人能在这里给我一个提示错误的提示。 将所有内容移动到新的MVC项目会非常非常耗时:-(

谢谢!

这看起来类似于System.InvalidCastException ,当在不同的上下文或不同的位置加载两次相同的程序集时,有时会抛出System.InvalidCastException 。 在MEF中的所有程序集加载都由AssemblyCatalog类使用Assembly.Load(AssemblyName)方法处理,该方法将在Load上下文中加载具有给定名称的程序集。 但是,在某些情况下 ,它会将它加载到LoadFrom上下文中,这有时会导致转换exception,例如您提到的exception:

无法将类型为“XY.HomeController(ContractName =”XY.HomeController“)”的基础导出值强制转换为“XY.HomeController”类型。

我要做的是查看包含XY.HomeController的程序集是否部署在多个位置。 如果它是一个强大的命名程序集,请不要忘记查看GAC。

Telerik的论坛中提到了类似的问题。

如果您想了解有关此主题的更多详细信息,请查看“运行时如何查找程序集” “程序集加载的最佳实践”以及Suzanne Cooks MSDN博客中的与负载相关的条目。

我有同样的问题,多次加载相同的程序集造成的。 将Contract添加到分离的项目和引用输出dll而不是直接引用项目将解决此问题。