私は、いくつかのアセンブリ (コア、ドメイン、バックエンド MVC、フロントエンド MVC など) に分割された、より大きな C# MVC 4 プロジェクトに取り組んでいます。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.<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;
}
すべてがこのように構成されています DependencyResolver.SetResolver(new CustomDependencyResolver(container)); ControllerBuilder.Current.SetControllerFactory(新しい SomeCustomControllerFactory(コンテナ));
補足: MEF2 RegistrationBuilder と、3 つの AssemblyCatalog と 1 つの DirectoryCatalog を持つ AggregateCatalog が使用されます。
メイン プロジェクト ソリューションから抽出し、新しい mvc 4 インターネット プロジェクト ソリューションを作成してそこに統合すると、すべてが完全に機能します。(2 つ目の単純なコア ライブラリを使用して、1 つのアセンブリでテストしました。)
私はすでにCompositionOptions.DisableSilentRejectionをオンにしました。そして、MEF関連のエラーをデバッグするためのこのリソースを見つけました HomeController 内のすべてを削除しました (空のコンストラクター、インポートなしなど)。MEF コンテナーには、適切なエクスポートが格納されます。すべて順調です。
丸一日のデバッグと調査の後、私は MEF について多くのことを学びましたが、それでも同じ問題を抱えています。うまくいけば、誰かが私にヒントを与えてくれることを願っています。すべてを新しい MVC プロジェクトに移動すると、非常に時間がかかります :-(
ありがとう!