2013-01-14 25 views
9

मैं एक बड़ा सी # MVC 4 परियोजना है जो कई विधानसभाओं (कोर, डोमेन, बैकएंड MVC, दृश्यपटल MVC आदि) में बांटा गया है पर काम कर रहा हूँ कोशिश कर रहा। मैं अधिकांश निर्भरताओं को लोड और हल करने के लिए एमईएफ द्वारा प्रदान की गई प्लगइन आर्किटेक्चर का उपयोग करता हूं। अब मैं यह भी चाहता था कि यह एमवीसी नियंत्रक लोड करने के लिए उपयोग करें। दर्जनों नमूनों में पाया गया विशिष्ट परिदृश्य।CompositionContractMismatchException जब MVC नियंत्रक के साथ MEF का उपयोग करने के

अपवाद का कहना है::

लेकिन मैं इस 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 इस तरह से कॉन्फ़िगर किया गया है निर्भरताResolver.SetResolver (नया कस्टम निर्भरता रीसोलवर (कंटेनर)); नियंत्रकबिल्डर .Current.SetControllerFactory (नया कुछ कस्टम कंट्रोलर फैक्टरी (कंटेनर));

साइड नोट: MEF2 RegistrationBuilder और तीन AssemblyCatalogs और एक DirectoryCatalog के साथ एक AggregateCatalog किया जाता है।

पूरी बात पूरी तरह से काम करता है अगर मैं इसे मुख्य परियोजना समाधान से निकालने के लिए और एक नया MVC 4 इंटरनेट परियोजना समाधान बना सकते हैं और वहाँ एकीकृत। (एक विधानसभा के साथ यह परीक्षण किया गया, एक दूसरे सरल कोर lib साथ।)

मैं पहले से ही CompositionOptions.DisableSilentRejection चालू। और इस संसाधन को एमईएफ से संबंधित त्रुटियों को डीबग करने के लिए मिला https://blogs.msdn.com/b/dsplaisted/archive/2010/07/13/how-to-debug-and-diagnose-mef-failures.aspx?Redirected=true मैंने होमकंट्रोलर (खाली कन्स्ट्रक्टर, कोई आयात इत्यादि) में सब कुछ हटा दिया। एमईएफ कंटेनर उपयुक्त निर्यात से भरा है। सब कुछ ठीक है।

डिबगिंग और अनुसंधान के एक पूरे दिन के बाद मैं MEF, लेकिन अभी भी एक ही समस्या होने के बारे में बहुत कुछ सीखा। उम्मीद है कि कोई मुझे एक संकेत दे सकता है यहां गलत चाहता है। कारण एक नया MVC परियोजना के लिए सब कुछ आगे बढ़ होगा बहुत बहुत समय लेने वाली :-(

धन्यवाद!

उत्तर

12

यह System.InvalidCastException है कि कभी कभी फेंक दिया जाता है जब एक ही विधानसभा अलग contexes में या से दो बार भरी हुई है के समान दिखता है विभिन्न स्थानों। एमईएफ में सभी असेंबली लोडिंग को AssemblyCatalog वर्ग द्वारा Assembly.Load(AssemblyName) विधि का उपयोग करके संभाला जा रहा है जो लोड संदर्भ में दिए गए नाम के साथ असेंबली लोड करेगा। हालांकि, certain conditions के तहत, यह लोडफ़्रॉम संदर्भ में लोड हो जाएगा और यह कभी-कभी इस तरह के एक के रूप में कास्टिंग अपवाद के कारण आप का उल्लेख:

प्रकार के अंतर्निहित निर्यात मूल्य नहीं दिया जा सकता "XY.HomeController (ContractName =" XY.HomeController ")" टाइप करने के लिए "XY.HomeController"।]

मुझे क्या होता विधानसभा अगर लग रहा है जिसमें XY.HomeController एक से अधिक स्थानों पर तैनात है। यदि यह एक मजबूत नामित असेंबली है तो जीएसी में देखना न भूलें।

Telerik's forum में एक समान समस्या का उल्लेख किया गया है।

यदि आप इस विषय पर अधिक जानकारी चाहते हैं तो "How the Runtime Locates Assemblies""Best Practices for Assembly Loading" पर और Suzanne Cooks MSDN blog में लोड-संबंधित प्रविष्टियों को देखें।

+0

आपके उत्तर के लिए धन्यवाद। आप सही हैं यह मूल रूप से एक सिस्टम है। InvalalidCastException। एक और दिन डिबगिंग और आपके लिंक पढ़ने के बाद मैंने इसे समझ लिया। कुछ कारणों से (मैं कुछ निर्भरताओं को कुछ डीडीएस के अंदर गहरी गहरी मानता हूं ??) मुझे पूरे बिन/* निर्देशिका के लिए एक और निर्देशिका सूची जोड़ना पड़ा - उसके बाद आलसी से कास्ट <>। नियंत्रक के लिए मूल्य पूरी तरह से काम करता है। – Andreas

+2

यह एक और मामला जहां यह हो सकता है "testResults" निर्देशिका है कि कुछ परीक्षण धावक आपके परीक्षण वाले निर्देशिका के अंतर्गत बनाते हैं। एमईएफ उन परीक्षण निर्देशिकाओं में भर्ती करेगा और उसी डीएलएल की प्रतियां पायेगा। –

+1

मुझे यह समस्या थी, लेकिन केवल एक ही समाधान से मेरा कोड चलाते समय। डीबगर को असेंबली लोड करना बंद कर देता है। – sdgfsdh