저는 여러 어셈블리 (코어, 도메인, 백엔드 MVC, 프론트 엔드 MVC 등)로 분할 된 더 큰 C# MVC 4 프로젝트에서 작업하고 있습니다. MEF에서 제공하는 플러그인 아키텍처를 사용하여 대부분의 종속성을로드하고 해결합니다. 이제 MVC 컨트롤러를로드하는 데 사용하기를 원했습니다. 일반적인 시나리오는 수십 개의 샘플에서 발견됩니다.MVC 컨트롤러에서 MEF를 사용하려고하면 CompositionContractMismatchException이 발생합니다.
예외는 말한다 :
는하지만이 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.<CreateSemiStronglyTypedLazy>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<string, object>>()
.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<object> GetServices(Type serviceType) {
var exports = _container.GetExports(serviceType, null, null);
var createdObjects = new List<object>();
if (exports.Any()) {
foreach (var export in exports) {
createdObjects.Add(export.Value);
}
}
return createdObjects;
}
복음 전도, erything이 이렇게 구성되었습니다. DependencyResolver.SetResolver (새 CustomDependencyResolver (container)); ControllerBuilder.Current.SetControllerFactory (새 SomeCustomControllerFactory (container));
사이드 노트 : MEF2 RegistrationBuilder와 3 개의 AssemblyCatalog 및 1 개의 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 (Empty 생성자, 가져 오기 없음 등)의 모든 것을 제거했습니다. MEF 컨테이너는 적절한 수출로 가득 차 있습니다. 다 괜찮아.
디버깅과 연구 하루 종일 MEF에 대해 많은 것을 배웠지 만 여전히 동일한 문제가 있습니다. 바라건대 누군가 나에게 힌트를 줄 수 있기를 바랍니다. 새로운 MVC 프로젝트에 이르기까지 모든 이동 원인이 될 것이다 아주 아주 많은 시간이 소요
감사합니다!
:-(
답장을 보내 주셔서 감사합니다. 당신은 기본적으로 System.InvalidCastException입니다. 디버깅과 링크를 읽은 다른 날 후에 나는 그것을 알아 낸 것입니다. 몇 가지 이유로 (일부 종속성을 일부 .dll의 깊숙한 부분에 깊이 있다고 가정합니다.) 전체 bin/* 디렉토리에 다른 DirectoryCatalog를 추가해야했습니다. * 그 이후 게으른 <>에서 컨트롤러로 값을 캐스팅하면 완벽하게 작동합니다. – Andreas
또 다른 경우는 일부 테스트 주자가 테스트가 포함 된 디렉토리 아래에 만드는 "TestResults"디렉토리입니다. MEF는 테스트 디렉토리로 돌아가서 동일한 DLL의 복사본을 찾습니다. –
다른 솔루션에서 코드를 실행하는 경우에만이 문제가 발생했습니다. 디버거가 어셈블리를로드하고 있음을 나타냅니다. – sdgfsdh