2010-07-06 34 views
5

Tôi cần serialize một số dữ liệu vào chuỗi. Chuỗi này sau đó được lưu trữ trong DB trong một cột đặc biệt SerializeData.Nối tiếp và phiên bản

Tôi đã tạo các lớp đặc biệt được sử dụng để tuần tự hóa.

[Serializable] 
public class SerializableContingentOrder 
{ 
    public Guid SomeGuidData { get; set; } 
    public decimal SomeDecimalData { get; set; } 
    public MyEnumerationType1 EnumData1 { get; set; } 
} 

serialization:

protected override string Serialize() 
{ 
    SerializableContingentOrder sco = new SerializableContingentOrder(this); 

    MemoryStream ms = new MemoryStream(); 
    SoapFormatter sf = new SoapFormatter(); 
    sf.Serialize(ms, sco); 
    string data = Convert.ToBase64String(ms.ToArray()); 
    ms.Close(); 
    return data; 
} 

Deserialization:

protected override bool Deserialize(string data) 
{ 
    MemoryStream ms = new MemoryStream(Convert.FromBase64String(data).ToArray()); 
    SoapFormatter sf = new SoapFormatter(); 

    SerializableContingentOrder sco = sf.Deserialize(ms) as SerializableContingentOrder; 
    ms.Close(); 
    return true; 
} 

Bây giờ tôi muốn có versioning hỗ trợ. Điều gì xảy ra nếu tôi thay đổi lớp SerializableContingentOrder. Tôi muốn có thể thêm các trường mới trong tương lai.

Tôi có phải chuyển sang nối tiếp DataContract không? Xin vui lòng cho tôi đoạn mã ngắn?

+2

Xem MSDN; 'SoapFormatter' là lỗi thời chính thức: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.soap.soapformatter.aspx –

+0

Tôi cần phải đặt câu hỏi tương tự nhưng một chút mở rộng của nó. Dữ liệu sẽ thay đổi chắc chắn, chúng ta có thể làm cho cấu trúc dữ liệu tự xử lý thay đổi tiếp theo không? –

Trả lời

8

tôi mạnh ủng hộ chống lưu trữ BinaryFormatter hoặc SoapFormatter dữ liệu trong cơ sở dữ liệu; đó là:

  • giòn
  • không phiên bản chịu
  • không nền tảng độc lập

BinaryFormatter là OK để truyền dữ liệu giữa các cụm NET (tại một đẩy), nhưng tôi muốn giới thiệu một nhiều bộ nối tiếp có thể dự đoán được. DataContractSerializer là một tùy chọn (như là JSON hoặc XmlSerializer), nhưng tôi sẽ không sử dụng NetDataContractSerializer cho tất cả các lý do tương tự ở trên. Tôi sẽ bị cám dỗ để sử dụng protobuf-net, vì đó là nhị phân hiệu quả trong một định dạng hiệu quả được biết đến, nền tảng độc lập và phiên bản khoan dung!

Ví dụ:

[DataContract] 
public class SerializableContingentOrder 
{ 
    [DataMember(Order=1)] public Guid SomeGuidData { get; set; } 
    [DataMember(Order=2)] public decimal SomeDecimalData { get; set; } 
    [DataMember(Order=3)] public MyEnumerationType1 EnumData1 { get; set; } 
} 

serialization:

protected override string Serialize() 
{ 
    SerializableContingentOrder sco = new SerializableContingentOrder(this); 
    using(MemoryStream ms = new MemoryStream()) { 
     Serializer.Serialize(ms, sco); 
     return Convert.ToBase64String(ms.ToArray()); 
    } 
} 

Deserialization:

protected override bool Deserialize(string data) 
{ 
    using(MemoryStream ms = new MemoryStream(Convert.FromBase64String(data)) { 
     SerializableContingentOrder sco = 
       Serializer.Deserialize<SerializableContingentOrder>(ms) 
    } 
    return true; 
} 
+0

1) Serializer.Serialize() là gì? Không gian tên/assemply nào thuộc về nó? 2) Cảm ơn bạn đã trả lời toàn diện như vậy, nhưng làm thế nào để bạn có nghĩa là "BinaryFormatter hoặc SoapFormatter là giòn"? Plese mở rộng một chút –

+2

Bạn không nên chủ trương chống lại việc lưu trữ thay vì * không * lưu trữ? :) Đừng hiểu sai cách này, tiếng Anh không phải là ngôn ngữ mẹ đẻ của tôi, do đó là câu hỏi. –

+0

@Captain Comic - 'Serializer' là (theo trả lời của tôi) protobuf-net. Re "không lưu trữ", nó là chính xác như bằng văn bản. Tôi ** không ** giới thiệu 'BinaryFormatter' cho mục đích lưu trữ. Re giòn: http://marcgravell.blogspot.com/2009/03/obfuscation-serialization-and.html –

3

Vì .NET 2.0 bạn có hỗ trợ Serialization Dung sai Phiên bản nếu bạn sử dụng BinaryFormatter. Các SoapFormatter cũng hỗ trợ một số tính năng khoan dung phiên bản nhưng không phải tất cả những tính năng được hỗ trợ bởi BinaryFormatter, cụ thể hơn khả năng chịu dữ liệu không liên quan không được hỗ trợ.

Để biết thêm thông tin, bạn nên kiểm tra:

Version Tolerant Serialization

+1

Theo kinh nghiệm của tôi, chuỗi tuần tự dung nạp "BinaryFormatter'" đơn giản là * không phải *. –

+0

@Marc Gravell, tôi sẽ dùng từ ngữ của bạn cho nó, nhưng bạn có thể giải thích về những vấn đề cụ thể mà bạn phải đối mặt không? –

+0

Đồng ý với Marc, VTS cho phép một số thay đổi trong mã, như thêm trường tùy chọn, nhưng rất khó để đảm bảo rằng tất cả các thay đổi tiếp theo sẽ là "VTS tương thích". – VladV

1

Cách đơn giản nhất là để trang trí các lĩnh vực mới với OptionalFieldAttribute. Nó không hoàn hảo nhưng nó có thể làm trong trường hợp của bạn.

+0

OptionalField không hoạt động trên các thành viên dữ liệu kiểu 'struct', như 'Guid'. "khi một lớp có trường cấu trúc, thì OptionalFieldAttribute sẽ ngừng hoạt động". Đọc tại đây: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

5

Bạn có hai lựa chọn nếu bạn muốn hỗ trợ phiên bản. Sử dụng DataContracts hoặc sử dụng Version Sequerant Serialization. Cả hai đều hợp lệ.

DataContacts xử lý việc tự động thêm và xóa các trường. Xem Data Contact VersioningBest Practices: Data Contract Versioning để biết thêm thông tin.

DataContact Ví dụ

[DataContract] 
public class ContingentOrder 
{ 
    [DataMember(Order=1)] 
    public Guid TriggerDealAssetID; 

    [DataMember(Order=2)] 
    public decimal TriggerPrice; 

    [DataMember(Order=3)] 
    public TriggerPriceTypes TriggerPriceType; 

    [DataMember(Order=4)] 
    public PriceTriggeringConditions PriceTriggeringCondition; 

} 

Version chịu serialization Ví dụ

// Version 1 
[Serializable] 
public class SerializableContingentOrder 
{ 
    public Guid TriggerDealAssetID; 
    public decimal TriggerPrice; 
    public TriggerPriceTypes TriggerPriceType; 
    // Omitted PriceTriggeringCondition as an example 
} 

// Version 2 
[Serializable] 
public class SerializableContingentOrder 
{ 
    public Guid TriggerDealAssetID; 
    public decimal TriggerPrice; 
    public TriggerPriceTypes TriggerPriceType; 

    [OptionalField(VersionAdded = 2)] 
    public PriceTriggeringConditions PriceTriggeringCondition; 

    [OnDeserializing] 
    void SetCountryRegionDefault (StreamingContext sc) 
    { 
     PriceTriggeringCondition = /* DEFAULT VALUE */; 
    } 

} 

Thông tin thêm về Version Tolerant Serialization. Đặc biệt lưu ý các phương pháp hay nhất ở cuối trang.

Lưu ý, DataContracts đã được giới thiệu trong .NET 3.5, do đó bạn có thể không có tùy chọn đó nếu bạn cần nhắm mục tiêu .NET 2.0.

HTH,

+1

OptionalField không hoạt động trên các thành viên dữ liệu kiểu 'struct', như 'Guid'. "khi một lớp có trường cấu trúc, thì OptionalFieldAttribute sẽ ngừng hoạt động". Đọc tại đây: http://bytes.com/topic/net/answers/850545-optionalfieldattribute-causing-augumentnullexception-deseria – Nayan

+0

Cảm ơn @Nayan, tôi không biết điều đó. Một giải pháp có thể có/giải pháp thay thế cho điều này sẽ là bọc cấu trúc bằng cách sử dụng 'Nullable '. – Dennis

Các vấn đề liên quan