2012-03-08 12 views
5

तो मेरे पास एक डब्ल्यूपीएफ प्रोजेक्ट है जो मेरे काम पर किसी अन्य प्रोजेक्ट द्वारा उपयोग किए जाने वाले डीएलएस में खींच रहा है। यह निर्भरताओं की गड़बड़ी है, मैं इस तकनीक का उपयोग यहां कर रहा हूं: निर्भरता को एक निष्पादन योग्य में एम्बेड करने के लिए http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-applicationविधानसभा को कॉल करते समय असेंबली रीसोल्व घटना आग लगती है। लोड (बाइट())

अब, जब मैं निर्भरताओं में से किसी एक के अंदर एक विशिष्ट विधि को बुला रहा हूं, तो मैंने असेंबली रिसोलव ईवेंट को मारा। मेरा OnResolveAssembly घटना चलता है, यह असेंबली को एक एम्बेडेड संसाधन (ठंडा!) के रूप में पाता है, और "असेंबली लौटाता है। लोड (assembyRawBytes)"। अगर मैंने इस बिंदु पर F11 मारा (OnResolveAssembly की शुरुआत में ब्रेकपॉइंट के साथ), मुझे अन्य एक ही ईवेंट में कॉल करें। यह भी एक ही असेंबली के लिए है (args.Name वही है)।

यदि मैं इसे चलाने देता हूं तो मैंने एक स्टैक ओवरफ़्लो मारा, क्योंकि मैं कभी भी इस रिकर्सिव इवेंट कॉलिंग से बचने के लिए प्रतीत नहीं कर सकता।

एमएसडीएन दस्तावेज़ वास्तव में नहीं कहते हैं जब असेंबली। लोड नहीं हो सकता है, FileNotFoundException या BadImageFormatException को छोड़कर।

मैंने विधानसभा को कॉल करने से पहले इस समय OnResolveAssembly को अनदेखा करने की कोशिश की है। लोड, लेकिन फिर मेरा आवेदन एक रहस्यमय मौत मर जाता है, यहां तक ​​कि वीएस के तहत भी यह poof चला जाता है।

मैं शायद यहां कई नियम तोड़ रहा हूं, लेकिन समस्याओं के बारे में कहां से शुरू करना है, इसके कुछ विचारों का स्वागत किया जाएगा।

मैं समस्याग्रस्त डीएलएल में चारों ओर पोकिंग शुरू करने जा रहा हूं यह देखने के लिए कि इसमें क्या गलत है (शायद यह मिश्रित असेंबली है)?

यहाँ मेरी OnResolveAssembly हैंडलर है:

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) 
{ 
    Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
    AssemblyName assemblyName = new AssemblyName(args.Name); 

    string path = assemblyName.Name + ".dll"; 

    if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false) 
    { 
     path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path); 
    } 
    using (Stream stream = executingAssembly.GetManifestResourceStream(path)) 
    { 
     if (stream == null) 
      return null; 

     byte[] assemblyRawBytes = new byte[stream.Length]; 
     stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); 
     assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes)); 
     return assemblyDictionary[assemblyName.Name]; 
    } 
} 

समय के लिए, मैं इसे अपने संसाधनों के सभी के माध्यम से पुनरावृत्ति और उन पर Assembly.Load का प्रयास, और पुनः प्राप्ति के लिए एक शब्दकोश में उन्हें भंडारण (द्वारा हल किया है OnResolveAssembly घटना) के दौरान:

[STAThread] 
public static void Main() 
{ 
    AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly; 
    Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
    string[] resources = executingAssembly.GetManifestResourceNames(); 
    foreach (string resource in resources) 
    { 
     if (resource.EndsWith(".dll")) 
     { 
      using (Stream stream = executingAssembly.GetManifestResourceStream(resource)) 
      { 
       if (stream == null) 
        continue; 

       byte[] assemblyRawBytes = new byte[stream.Length]; 
       stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); 
       try 
       { 
        assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes)); 
       } 
       catch (Exception ex) 
       { 
        System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message); 
       } 
      } 
     } 
    } 
    App.Main(); 
} 

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) 
{ 
    Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
    AssemblyName assemblyName = new AssemblyName(args.Name); 

    string path = assemblyName.Name + ".dll"; 

    if (assemblyDictionary.ContainsKey(path)) 
    { 
     return assemblyDictionary[path]; 
    } 
    return null; 
} 

अब यह ठीक काम कर रहा हो लगता है ("में नाकाम रहने के" विधानसभा मेरी दूसरी स्निपेट में ठीक से लोड होगा), लेकिन मैं क्यों यह काम नहीं करता जानने के लिए दिलचस्पी होगी प्रथम।

+2

एक कोड स्निपेट आवश्यक है। –

+0

मैंने अपना कोड और एक वर्कअराउंड जोड़ा जो मैंने खोजा। –

+0

@ जोनाथनवाई क्या आपको वास्तव में 'असेंबली रीसोल्व' को कॉल के अंदर से 'असेंबली' लोड (बाइट []) 'में लिया गया है? यह वही मामला है जिसे मैं ढूंढ रहा हूं [यहां] (http://stackoverflow.com/questions/24718917/can-a-call-to-assembly-loadbyte-raise-the-appdomain-assemblyresolve-event), लेकिन मैं ऐसा उदाहरण नहीं बना सका। क्या आप अधिक जानकारी प्रदान कर सकते हैं? –

उत्तर

3

बाइट [] से एक असेंबली लोड करना .dll नरक (जिस स्थान पर आप बहुत अधिक/जटिल निर्भरताओं के लिए जाते हैं) में समाप्त होने का एक अच्छा तरीका है। यहां समस्या यह है कि यद्यपि आपने ऐपडोमेन को डीएल लोड किया है, लेकिन जब आपको इसकी आवश्यकता होती है तो इसे स्वचालित रूप से हल नहीं किया जाता है, जब आपको निर्भर करता है तो निर्भर प्रकार के लिए। मैंने इस समस्या पर टिप्पणी की: AssemblyResolve Does not fire

लंबी कहानी छोटी, Assemblies को AppDomains के अंदर विभिन्न "संदर्भ" में लोड किया जाता है। लोड (बाइट []) द्वारा उपयोग किया गया संदर्भ स्वचालित रूप से असेंबली को हल नहीं करता है।

समाधान लोड किए गए असेंबली का ट्रैक रख रहा है और इसे दूसरी बार लोड करने के बजाय पहले से लोड की गई असेंबली को वापस कर रहा है। मेरे उत्तर में इस दृष्टिकोण के लिए एक शुरुआती बिंदु है: Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true

लेकिन मुझे लगता है कि आपको अपने कामकाज के साथ यह सही मिला है।

बीटीडब्ल्यू। एक असेंबली दो बार लोड करना एक समान लेकिन असंगत प्रकार प्राप्त करने का एक तरीका है। कभी भी MyType से MyType से MyType में एक ही असेंबली से MyType में ऑब्जेक्ट डाला और शून्य हो गया?

यह गर्म है ".dll नरक में आपका स्वागत है"।

संबंधित मुद्दे