2013-01-14 16 views
9

私は、いくつかのアセンブリ(コア、ドメイン、バックエンド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; 
    } 

のEv erythingはこのように設定されています DependencyResolver.SetResolver(new CustomDependencyResolver(container)); ControllerBuilder.Current.SetControllerFactory(新しいSomeCustomControllerFactory(container));

サイドノート:MEF2 RegistrationBuilderと、3つのAssemblyCatalogと1つのDirectoryCatalogを持つAggregateCatalogが使用されています。

メインプロジェクトソリューションから抽出し、新しいmvc 4インターネットプロジェクトソリューションを作成してそこに統合すると、すべてが完璧に機能します。 (1つのアセンブリで2番目のシンプルなコアライブラリでテスト済み)

私は既に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プロジェクトにすべてを移動する原因は、非常に非常に時間がかかる。これは、同じアセンブリが異なるcontexesにまたはから2回ロードされたときに、時にはスローされるSystem.InvalidCastExceptionに似:-(

ありがとう!

答えて

12

だろうMEFのすべてのアセンブリのロードはAssembly.Load(AssemblyName)メソッドを使用してAssemblyCatalogクラスによって処理されていますが、Loadコンテキストで指定された名前のアセンブリをロードしますが、certain conditionsの下ではLoadFromコンテキストにロードされますあなたが言及したようなキャスト例外を発生させます:

は 「XY.HomeController」と入力するタイプ の基礎となるエクスポート値「XY.HomeController(ContractName =」XY.HomeControllerを「)」にキャストすることはできません。]

私はどうなるのかは、組み立てた場合に見ていますXY.HomeControllerが含まれており、複数の場所に展開されています。強力な名前のついたアセンブリであるかどうかをGACで調べることを忘れないでください。

同様の問題がTelerik's forumに記載されています。

この件に関する詳細は、"How the Runtime Locates Assemblies""Best Practices for Assembly Loading"と、負荷関連のエントリSuzanne Cooks MSDN blogをご覧ください。

+0

あなたの答えをありがとう。あなたは基本的にSystem.InvalidCastExceptionです。別の日のデバッグとあなたのリンクを読んだ後、私はそれを理解しました。いくつかの理由で(一部の.dllの深いところまで依存関係があると仮定しています)、私はbin /ディレクトリ全体に対して別のDirectoryCatalogを追加しなければなりませんでした。 – Andreas

+2

これが発生する可能性がある別のケースは、テストを含むディレクトリの下にテストランナーが作成する "TestResults"ディレクトリです。 MEFはこれらのテストディレクトリを再帰し、同じDLLのコピーを探します。 –

+1

私はこの問題を抱えていましたが、別のソリューションから自分のコードを実行しているときだけでした。デバッガがアセンブリをロードしていたことを示します。 – sdgfsdh

関連する問題