2010-01-22 31 views
13

tôi nhận được một:BinaryFormatter deserialize cho SerializationException

System.Runtime.Serialization.SerializationException: Không thể tìm lắp ráp 'MyNameSpace, Version = 1.0.0.0, Culture = trung tính, PublicKeyToken = null

Khi cố gắng deserialize một số dữ liệu trong một chương trình khác với chương trình tôi đã tuần tự hóa nó.

Sau khi một số googling tôi đã phát hiện ra rằng dường như điều này chỉ có thể được thực hiện bằng cách sử dụng một hội đồng chia sẻ.

Tuy nhiên, cơ sở dữ liệu của tôi đầy với các đối tượng được tuần tự hóa này và tôi cần một chương trình tiện ích để loại bỏ chúng. Có cách nào để ghi đè lên hành vi này và chỉ cần ăn nó cùng một lớp học chính xác và buộc nó làm deserialize?


Tôi đã tìm thấy đoạn mã này, nhưng tôi không hiểu cách thức và nơi tôi nên đặt/sử dụng.

static constructor() { 
     AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
    } 

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { 
     Assembly ayResult = null; 
     string sShortAssemblyName = args.Name.Split(',')[0]; 
     Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies(); 
     foreach (Assembly ayAssembly in ayAssemblies) { 
      if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0]) { 
       ayResult = ayAssembly; 
       break; 
      } 
     } 
     return ayResult; 
    } 
+1

Tham chiếu lắp ráp ban đầu trong ứng dụng tiện ích của bạn không phải là một lựa chọn? –

+0

@eric: một số chỉ chưa được trả lời ... vì vậy tôi không thể chấp nhận chúng. Nhưng tôi sẽ xem lại chúng một lần nữa để xem câu trả lời/bình luận mới đã được thêm – Toad

+0

bất kỳ giải pháp cuối cùng nào với mẫu mã nguồn đầy đủ chưa? – Kiquenet

Trả lời

6

Bạn sẽ cần phải cung cấp một tham chiếu đến các loại gốc bằng cách nào đó để chương trình tiện ích biết làm thế nào để deserialize nó.

Cách dễ dàng chỉ là thêm DLL các loại ban đầu được định nghĩa trong như một tham chiếu đến dự án tiện ích.

Mã bạn đã đăng cho phép bạn tải động cùng một DLL đó khi trình khử giải quyết định không thể tìm thấy loại đó. Đây là một cách tiếp cận khó khăn hơn (nhưng không phải là rằng khó), nhưng trong cả hai trường hợp, bạn sẽ cần một DLL xác định các loại ... vì vậy có lẽ dễ nhất chỉ để liên kết tĩnh bằng cách thêm tham chiếu.

Nếu các loại của bạn hiện không nằm trong tệp DLL (ví dụ: nếu chúng ở trong EXE), tôi đề nghị bạn kéo các lớp ra khỏi EXE thành một DLL mới, và tham khảo DLL đó từ dự án gốc và từ dự án util.

+0

Tuyệt vời! Tôi đã thực sự chỉ tham chiếu toàn bộ .exe chỉ để xem nó có hoạt động hay không, và tôi có thể tham khảo không gian tên và các lớp. Cảm ơn vì tiền hỗ trợ! – Toad

13

Bạn có thể khắc phục vấn đề này mà không cần các DLL nếu bạn biết đối tượng ...

http://spazzarama.com/2009/06/25/binary-deserialize-unable-to-find-assembly/

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder(VS.71).aspx

Sử dụng các lớp “System.Runtime.Serialization.SerializationBinder” . Bởi kế thừa từ lớp này, bạn có thể chuyển hướng tất cả các yêu cầu cho các loại từ trình định dạng nhị phân đến các loại bạn chọn.

Đây là một mẫu mà sẽ cho phép các loại được tìm thấy trong lắp ráp hiện nay bất kể là phiên bản của hội đồng ban đầu được tạo ra dòng tuần tự:

sealed class AllowAllAssemblyVersionsDeserializationBinder : System.Runtime.Serialization.SerializationBinder 
{ 
    public override Type BindToType(string assemblyName, string typeName) 
    {  
     String currentAssembly = Assembly.GetExecutingAssembly().FullName; 

     // In this case we are always using the current assembly 
     assemblyName = currentAssembly; 

     // Get the type using the typeName and assemblyName 
     Type typeToDeserialize = Type.GetType(String.Format("{0}, {1}", 
      typeName, assemblyName)); 

     return typeToDeserialize; 
    } 
} 

public static MyRequestObject Deserialize(byte[] b) 
{ 
    MyRequestObject mro = null; 
    var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
    using (var ms = new System.IO.MemoryStream(b)) 
    { 
     // To prevent errors serializing between version number differences (e.g. Version 1 serializes, and Version 2 deserializes) 
     formatter.Binder = new AllowAllAssemblyVersionsDeserializationBinder(); 

     // Allow the exceptions to bubble up 
     // System.ArgumentNullException 
     // System.Runtime.Serialization.SerializationException 
     // System.Security.SecurityException 
     mro = (MyRequestObject)formatter.Deserialize(ms); 
     ms.Close(); 
     return mro; 
    } 
} 
+0

Cảm ơn! Tôi bắt đầu với điều này, nhưng đã phải sửa đổi rất nhiều mã cho trường hợp sử dụng của tôi. Xem câu trả lời của tôi ở đây: http://stackoverflow.com/a/25412474/1339280 – shoelzer

+1

Tại sao 'ms.Close()'? Không phải là tuyên bố sử dụng chăm sóc đó? –

+0

vâng ... chắc chắn là dự phòng, đoán được sao chép từ một câu lệnh không sử dụng và không bao giờ gỡ bỏ – JTtheGeek

1

Nếu bạn không có quyền truy cập vào các hội đồng ban đầu mà serialized dữ liệu, sau đó bạn có thể sử dụng một SerializationBinder hoặc một SerializationSurrogate. Hai giao diện này cho phép bạn kiểm soát cách các loại được chuyển đổi giữa nhau khi deserializing.

4

Tôi chạy vào một vấn đề tương tự và tôi đã nhận nó làm việc với sự giúp đỡ của liên kết sau: BinaryFormatterDeserialize-not-finding-a-type

Về cơ bản những gì bạn cần làm là đăng ký vào các sự kiện AssemblyResolve TRƯỚC deserializing. Sau đó bỏ đăng ký sau khi deserialization ..

AppDomain.CurrentDomain.AssemblyResolve += 
       new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
// CODE TO DESERIALIZE HERE 

AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve); 

Ở đây phương pháp này tôi đã sử dụng để giải quyết các hội:

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    try 
    { 
     if(args.Name == "MY ASSEMBLY NAME")) 
     { 
      //Load my Assembly 
      Assembly assem = Assembly.LoadFrom("MY ASSEMBLY PATH"); 
      if(assem != null) 
       return assem; 
     } 
    } 
    catch { ;} 

    return Assembly.GetExecutingAssembly(); 
} 
+0

kỹ thuật này làm việc cho tôi khi tôi không có quyền truy cập vào phiên bản cụ thể của hội đồng để deserialization nhưng tôi biết phiên bản hiện tại tương thích với nó. – Mike

0

Tôi làm theo các giải pháp đã trả lời bởi JTtheGeek và để có được nó làm việc cho tôi, tôi đã có thêm sau đây ngay trước tuyên bố assemblyName = currentAssembly;:

typeName = "yourNamespace.yourClassName"; 

Sau đó, nó hoạt động rất tốt!

4

JTtheGeek's answer đúng là tùy chỉnh SerializationBinder là cách xử lý vấn đề này. Ví dụ, mã ví dụ được đưa ra trong câu trả lời đó không đủ cho trường hợp sử dụng của tôi. Tôi cần một cái gì đó có thể:

  1. Xử lý các số phiên bản không khớp không gian tên.
  2. Nhìn vào tất cả các cụm, không chỉ là cụm hiện tại.
  3. Vẫn đủ nhanh để gọi 100 lần mỗi giây.

Đây là những gì tôi đã đưa ra:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace Company.Product.Common.Serialize 
{ 
    /// <summary> 
    /// A Serialization Binder that allows inexact matches (version number or namespace). 
    /// </summary> 
    public sealed class AllowInexactMatchSerializationBinder : System.Runtime.Serialization.SerializationBinder 
    { 
     static private Dictionary<string, Type> typeBindings = new Dictionary<string, Type>(); 

     /// <summary> 
     /// When overridden in a derived class, controls the binding of a serialized object to a type. 
     /// </summary> 
     /// <param name="assemblyName">Specifies the <see cref="T:System.Reflection.Assembly" /> name of the serialized object.</param> 
     /// <param name="typeName">Specifies the <see cref="T:System.Type" /> name of the serialized object.</param> 
     /// <returns> 
     /// The type of the object the formatter creates a new instance of. 
     /// </returns> 
     public override Type BindToType(string assemblyName, string typeName) 
     { 
      Type type; 
      var assemblyQualifiedTypeName = String.Format("{0}, {1}", typeName, assemblyName); 

      // use cached result if it exists 
      if (typeBindings.TryGetValue(assemblyQualifiedTypeName, out type)) 
      { 
       return type; 
      } 

      // try the fully qualified name 
      try { type = Type.GetType(assemblyQualifiedTypeName); } 
      catch { type = null; } 

      if (type == null) 
      { 
       // allow any assembly version 
       var assemblyNameWithoutVersion = assemblyName.Remove(assemblyName.IndexOf(',')); 
       var assemblyQualifiedTypeNameWithoutVersion = String.Format("{0}, {1}", typeName, assemblyNameWithoutVersion); 
       try { type = Type.GetType(assemblyQualifiedTypeNameWithoutVersion); } 
       catch { type = null; } 
      } 

      if (type == null) 
      { 
       // check all assemblies for type full name 
       try 
       { 
        type = AppDomain.CurrentDomain.GetAssemblies() 
         .SelectMany(a => a.ExportedTypes) 
         .Where(a => a.FullName == typeName) 
         .FirstOrDefault(); 
       } 
       catch { type = null; } 
      } 

      if (type == null) 
      { 
       // check all assemblies for type name 
       var name = typeName.Split('.').Last(); 
       try 
       { 
        type = AppDomain.CurrentDomain.GetAssemblies() 
         .SelectMany(a => a.ExportedTypes) 
         .Where(a => a.Name == name) 
         .FirstOrDefault(); 
       } 
       catch { type = null; } 
      } 

      typeBindings[assemblyQualifiedTypeName] = type; 
      return type; 
     } 
    } 
} 
Các vấn đề liên quan