2011-03-02 16 views
9

के बाद "असेंबली ढूंढने में असमर्थ" को संदर्भित करें मेरे पास एक संदर्भित डीएल (एक ही .NET संस्करण के साथ सी #) के साथ एक सी # समाधान है। जब मैं समाधान का निर्माण करता हूं और परिणामस्वरूप exe चलाता हूं, exe और संदर्भित डीएल विलय किए बिना, सब कुछ ठीक काम करता है।बाइनरीफॉर्मेटर। ILMerge

अब मैं इन्हें एक एक्सई में विलय करना चाहता हूं। मैं ILMerge चलाता हूं और सबकुछ ठीक काम करता प्रतीत होता है। मैं exe निष्पादित करने का प्रयास करता हूं और ऐसा लगता है जब तक कि संदर्भित डीएल में परिभाषित किसी ऑब्जेक्ट को deserialize करने की कोशिश नहीं करता है।

using (Stream fstream = new FileStream(file_path, FileMode.Open)) 
{ 
    BinaryFormatter bf = new BinaryFormatter(); 
    return bf.Deserialize(fstream) as ControlledRuleCollection; 
    // throws unable to find assembly exception 
} 

क्या शायद कुछ आईएलएमर्ज विकल्प मैं यहां याद कर रहा हूं?

+3

था वस्तु पूर्व मर्ज विधानसभाओं या विधानसभाओं मर्ज के बाद से धारावाहिक? –

+1

मुझे यह कहने से नफरत है, लेकिन फिर भी एक और कारण है कि मैं हमेशा लोगों को बाइनरीफॉर्मेटर का उपयोग करने से हतोत्साहित करने की कोशिश करता हूं। मेटाडाटा टाइप करने के लिए यह बहुत करीब-करीब युग्मन दर्द की भारी मात्रा का कारण बनता है। यदि आप भविष्य में इस (और कई अन्य दर्द परिदृश्य) से बचने में रुचि रखते हैं तो मैं बेहतर विकल्पों की सिफारिश कर सकता हूं। –

+6

आप जानते हैं कि बाइनरी क्रमबद्धता भंडारण प्रारूप के लिए नहीं है, है ना? यह केवल एक अस्थायी परिवहन प्रारूप होने का मतलब है, बाइनरी धारावाहिक के माध्यम से किए जाने वाले ऑब्जेक्ट्स के दीर्घकालिक भंडारण के लिए बहुत सी सीमाएं हैं। अपने प्रोग्राम को अपग्रेड करें और पुरानी फाइलों को अलविदा करें। –

उत्तर

7

ऐसा लगता है कि आप एक DLL के अंदर एक वस्तु धारावाहिक है, तो ILMerge साथ विधानसभाओं के सभी विलय कर दिया और अब उस वस्तु deserialize करने की कोशिश कर रहे हैं। यह बस काम नहीं करेगा। द्विआधारी क्रमिकरण के लिए deserialization प्रक्रिया मूल डीएलएल से वस्तु के प्रकार को लोड करने का प्रयास करेगा। यह डीएलएल आईएलएमर्ज के बाद मौजूद नहीं है और इसलिए deserialization विफल हो जाएगा।

क्रमबद्धता और deserialization प्रक्रिया दोनों पूर्व या पोस्ट विलय संचालित करने की आवश्यकता है। यह

3

आप अलग असेंबली से क्रमबद्ध हो सकते हैं और फिर इसे किसी अन्य असेंबली (या एक ही असेंबली का एक नया संस्करण) के साथ deserialize करने की कोशिश की।

कुछ चर्चा here

0

नहीं मिलाया जा सकता यदि आप एक मौजूदा एक में विधानसभाओं विलय (के लिए-उदाहरण EXE करने के लिए सभी DLLs) मामले में आप समाधान this answer में प्रस्तावित उपयोग कर सकते हैं:

// AssemblyInfo.cs for My.exe 
[assembly: TypeForwardedTo(typeof(SomeTypeFromMergedDLL))] 

यह कम से कम के लिए काम करता पूर्व विलय deserializing। आईएल-मर्ज अभी भी गुजरता है; भले ही आप एक ही असेंबली के प्रकार के लिए एक प्रकार के आगे संकलित नहीं कर सकते ...

मैंने कोशिश नहीं की है, अगर सीरियलाइजिंग अभी भी विलय के बाद काम करता है। लेकिन मैं अपना जवाब अपडेट रखूंगा।

33

आप इसे सीरियलाइजेशन बाइंडर उप वर्ग बनाकर जोड़कर कर सकते हैं जो deserialization होने से पहले असेंबली नाम बदल देगा।

sealed class PreMergeToMergedDeserializationBinder : SerializationBinder 
{ 
    public override Type BindToType(string assemblyName, string typeName) 
    { 
     Type typeToDeserialize = null; 

     // For each assemblyName/typeName that you want to deserialize to 
     // a different type, set typeToDeserialize to the desired type. 
     String exeAssembly = Assembly.GetExecutingAssembly().FullName; 


     // The following line of code returns the type. 
     typeToDeserialize = Type.GetType(String.Format("{0}, {1}", 
      typeName, exeAssembly)); 

     return typeToDeserialize; 
    } 
} 

फिर जब deserializating BinaryFormatter से जोड़ें:

BinaryFormatter bf = new BinaryFormatter(); 
bf.Binder = new PreMergeToMergedDeserializationBinder(); 
object obj = bf.Deserialize(ms); 
+1

उत्कृष्ट जवाब! यह मुझे बहुत समय बचाया! धन्यवाद! – gleng

0

मैं एक स्थिति है जहाँ धारावाहिक डेटा एक पुराने नेट सेवा उस जगह में वर्षों के लिए किया गया था द्वारा एसक्यूएल सर्वर में संग्रहित किया जा रहा था था। मुझे एसक्यूएल से डेटा प्राप्त करने की आवश्यकता थी और इसमें भी भाग गया। मैं .exe को संदर्भित करने में सक्षम था और इसे तब तक काम करता था जब तक मैंने ऊपर उल्लिखित समाधान का उपयोग नहीं किया। हालांकि मेरे असेंबली नाम अलग थे।

sealed class Version1ToVersion2DeserializationBinder : SerializationBinder 
    { 
     public override Type BindToType(string assemblyName, string typeName) 
     { 
      Type typeToDeserialize = null; 

      // For each assemblyName/typeName that you want to deserialize to a different type, set typeToDeserialize to the desired type. 
      String assemVer1 = assemblyName; 
      String typeVer1 = typeName; 

      if (assemblyName == assemVer1 && typeName == typeVer1) 
      { 
       // To use a type from a different assembly version, change the version number. 
       assemblyName = Assembly.GetExecutingAssembly().FullName; 
       // To use a different type from the same assembly, change the type name. 
       typeName = "projectname.typename"; 
      } 

      // The following line of code returns the type. 
      typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName)); 
      return typeToDeserialize; 
     } 
    } 
0

मैं समाधान

sealed class VersionDeserializationBinder : SerializationBinder 
    { 
    public override Type BindToType(string assemblyName, string typeName) 
    { 
    Type typeToDeserialize = null; 
    string currentAssemblyInfo = Assembly.GetExecutingAssembly().FullName; 

    //my modification 
    string currentAssemblyName = currentAssemblyInfo.Split(',')[0]; 
    if (assemblyName.StartsWith(currentAssemblyName))assemblyName = currentAssemblyInfo; 

    typeToDeserialize = Type.GetType(string.Format("{0}, {1}", typeName, assemblyName)); 
    return typeToDeserialize; 
} 

}

Deserialization problem: Error when deserializing from a different program version

0
public sealed class DeserializationBinder : SerializationBinder 
{ 
    private readonly string _typeName; 
    private readonly Assembly _assembly; 
    public DeserializationBinder(Assembly assembly, string typeName) 
    { 
     _typeName = typeName; 
     _assembly = assembly; 
    } 

    public override Type BindToType(string assemblyName, string typeName) 
    { 
     Type typeToDeserialize = null; 
     if (!assemblyName.Contains("System") && !assemblyName.Contains("mscorlib")) 
     { 
      String currentAssembly = _assembly.FullName; 
      assemblyName = currentAssembly; 
      typeName = _typeName; 
     } 
     typeToDeserialize = Type.GetType(String.Format("{0}, {1}", 
      typeName, assemblyName)); 
     return typeToDeserialize; 
    } 
} 
+1

आपके उत्तर में कुछ विवरण देना एक अच्छा विचार होगा। – julienc

1

SerializationBinder भी मेरी समाधान था मिल गया। लेकिन मेरे पास एक डीएलएल में कक्षा है जिसका संदर्भ दिया गया है। तो मुझे सभी लोड असेंबली में खोजना है।यदि बाइंडर को डीएलएस में खोजना चाहिए तो मैंने पैरामीटर के साथ उत्तर बीवर को संशोधित किया है।

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Reflection; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters.Binary; 

namespace ibKastl.Helper 
{ 
    public static class BinaryFormatterHelper 
    { 
     public static T Read<T>(string filename, Assembly currentAssembly) 
     { 
     T retunValue; 
     FileStream fileStream = new FileStream(filename, FileMode.Open); 

     try 
     { 
      BinaryFormatter binaryFormatter = new BinaryFormatter(); 
      binaryFormatter.Binder = new SearchAssembliesBinder(currentAssembly,true);    
      retunValue = (T)binaryFormatter.Deserialize(fileStream); 
     } 
     finally 
     { 
      fileStream.Close(); 
     } 

     return retunValue; 
     } 

     public static void Write<T>(T obj, string filename) 
     { 
     FileStream fileStream = new FileStream(filename, FileMode.Create); 
     BinaryFormatter formatter = new BinaryFormatter(); 
     try 
     { 
      formatter.Serialize(fileStream, obj); 
     } 
     finally 
     { 
      fileStream.Close(); 
     } 
     } 
    } 

    sealed class SearchAssembliesBinder : SerializationBinder 
    { 
     private readonly bool _searchInDlls; 
     private readonly Assembly _currentAssembly; 

     public SearchAssembliesBinder(Assembly currentAssembly, bool searchInDlls) 
     { 
     _currentAssembly = currentAssembly; 
     _searchInDlls = searchInDlls; 
     } 

     public override Type BindToType(string assemblyName, string typeName) 
     { 
     List<AssemblyName> assemblyNames = new List<AssemblyName>(); 
     assemblyNames.Add(_currentAssembly.GetName()); // EXE 

     if (_searchInDlls) 
     { 
      assemblyNames.AddRange(_currentAssembly.GetReferencedAssemblies()); // DLLs 
     } 

     foreach (AssemblyName an in assemblyNames) 
     { 
      var typeToDeserialize = GetTypeToDeserialize(typeName, an); 
      if (typeToDeserialize != null) 
      { 
       return typeToDeserialize; // found 
      } 
     } 

     return null; // not found 
     } 

     private static Type GetTypeToDeserialize(string typeName, AssemblyName an) 
     { 
     string fullTypeName = string.Format("{0}, {1}", typeName, an.FullName); 
     var typeToDeserialize = Type.GetType(fullTypeName); 
     return typeToDeserialize; 
     } 
    } 

} 

उपयोग:

const string FILENAME = @"MyObject.dat"; 

// Serialize 
BinaryFormatterHelper.Write(myObject1,FILENAME); 

// Deserialize 
MyObject myObject2 = BinaryFormatterHelper.Read<MyObject>(FILENAME, Assembly.GetExecutingAssembly()); // Current Assembly where the dll is referenced 
संबंधित मुद्दे