10

Có ai biết về bất kỳ vấn đề nào khi sử dụng ProtoBuf-Net để tuần tự hóa/deserialize giữa khung nhỏ gọn và khung .Net đầy đủ không? Tôi có một lớp được gọi là LogData mà tôi đang tuần tự hóa theo khuôn khổ nhỏ gọn 3.5, truyền đến một máy chủ (chạy .Net framework 4.0), mà sau đó deserializes. Đôi khi nó hoạt động và đôi khi nó ném lỗi trên và tôi chưa thu hẹp nó xuống bất kỳ nguyên nhân cụ thể nào. Tôi đã thực hiện rất nhiều bài kiểm tra với các giá trị khác nhau và dường như không tìm thấy bất kỳ vần điệu hoặc lý do nào khi xảy ra lỗi. Tôi bao gồm các lớp học của tôi dưới đây (trừ các nhà xây dựng khác nhau). Tôi đã xem xét bộ đệm byte ở hai bên nhiều lần và chưa tìm thấy sự khác biệt trong dữ liệu được gửi qua dây từ bên này sang bên kia.Lỗi "Trường không hợp lệ trong dữ liệu nguồn: 0" với khung ProtoBuf-Net và Compact

[ProtoContract] 
public class LogData 
{ 

    [ProtoContract] 
    public enum LogSeverity 
    { 
    [ProtoEnum(Name = "Information", Value = 0)] 
    Information, 
    [ProtoEnum(Name = "Warning", Value = 1)] 
    Warning, 
    [ProtoEnum(Name = "Error", Value = 2)] 
    Error, 
    [ProtoEnum(Name = "Critical", Value = 3)] 
    Critical 
    } 

    [ProtoMember(1)] 
    public string UserID { get; set; } 
    [ProtoMember(2)] 
    public string ComputerName { get; set; } 
    [ProtoMember(3)] 
    public ExceptionProxy Exception { get; set; } 
    [ProtoMember(4)] 
    public LogData.LogSeverity Severity { get; set; } 
    [ProtoMember(5)] 
    public string Source { get; set; } 
    [ProtoMember(6)] 
    public string Caption { get; set; } 
    [ProtoMember(7)] 
    public string Description { get; set; } 
    [ProtoMember(8)] 
    public DateTime TimeOfOccurrence { get; set; } 
    [ProtoMember(9)] 
    public Guid SessionID { get; set; } 
    [ProtoMember(10)] 
    public string MethodName { get; set; } 
    [ProtoMember(11)] 
    public string OSVersion { get; set; } 
    [ProtoMember(12)] 
    public string Category { get; set; } 
    [ProtoMember(13)] 
    public string Location { get; set; } 
} 

[ProtoContract] 
public class ExceptionProxy 
{ 

    [ProtoMember(1)] 
    public Type ExceptionType { get; set; } 
    [ProtoMember(2)] 
    public string Message { get; set; } 
    [ProtoMember(3)] 
    public string StackTrace { get; set; } 
    [ProtoMember(4)] 
    public ExceptionProxy InnerException { get; set; } 

} 

Đây là mã của tôi mà không được serialization và gửi

private void WriteLogDataToServer(LogData data) 
    { 
    using (var client = new TcpClient()) 
    { 
     client.Connect(Host, SignalLineServerPort); 
     using (var stream = client.GetStream()) 
     { 
      using (var ms = new MemoryStream()) 
      { 
       Serializer.Serialize<LogData>(ms, data); 
       var buffer = ms.GetBuffer(); 
       int position = 0; 
       WriteFrameMarkers(stream); 
       byte[] frameLengthBuffer = BitConverter.GetBytes(buffer.Length); 
       stream.Write(frameLengthBuffer, 0, IntByteSize); 
       while (position < buffer.Length) 
       { 
       int length = Math.Min(ChunkSize, buffer.Length - position); 
       stream.Write(buffer, position, length); 
       position += ChunkSize; 
       } 
      } 
     } 
     client.Close(); 
    }   
    } 

Và đây là đoạn code mà đọc dữ liệu trên máy chủ

public override LogData ReadData(NetworkStream stream) 
    { 
    if (stream.DataAvailable) 
    { 
     try 
     { 
      const int chunkSize = 250; 
      byte[] buffer = new byte[IntByteSize]; 
      int messageSize = 0; 
      int totalBytesRead = 0; 
      LogData data; 
      using (var ms = new MemoryStream()) 
      { 
       if (!ReadFrameMarkers(stream)) 
       return null; 
       totalBytesRead = stream.Read(buffer, 0, IntByteSize); 
       if (totalBytesRead != IntByteSize) 
       return null; 
       messageSize = BitConverter.ToInt32(buffer, 0); 
       totalBytesRead = 0; 
       while ((totalBytesRead < messageSize)) 
       { 
       int bufferSize = Math.Min(chunkSize, messageSize - totalBytesRead); 
       buffer = new byte[bufferSize]; 
       int bytesRead = stream.Read(buffer, 0, bufferSize); 
       if (bytesRead != 0) 
       { 
        totalBytesRead += bytesRead; 
        ms.Write(buffer, 0, bytesRead); 
       } 
       } 
       ms.Seek(0, SeekOrigin.Begin); 
       data = Serializer.Deserialize<LogData>(ms); 
      } 
      return data; 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(string.Format("Error occurred: {0}", ex.Message)); 
      return null; 
     } 
    } 
    return null; 
    } 
+1

Tôi có thể xem mã bạn đang sử dụng để: serialize, gửi đến dây, đọc từ dây, deserialize không? Đặt cược mạnh mẽ của tôi là bạn đã vô tình để lại một số padding 0 trong một bộ đệm, mà không giới hạn độ dài để đọc. –

+0

Tôi đã chỉnh sửa bài đăng để bao gồm mã tuần tự hóa và deserialize. Tôi đã bỏ qua mã dây dẫn xử lý việc thương lượng chấp nhận các kết nối và như vậy. Nếu bạn cần thêm bất kỳ chi tiết nào trên mã, hãy cho tôi biết. Cảm ơn Marc rất nhiều. – WiredWiz

Trả lời

13

dễ dàng một: bạn sử dụng:

var buffer = ms.GetBuffer(); 

Và sau đó buffer.Length. Điều đó có nghĩa là bạn đang sử dụng bộ đệm đệm quá khổ. Nếu bạn làm điều đó, bạn cần sử dụng ms.Length, sẽ cho bạn biết số lượng thực tế. Ngoài ra, ms.ToArray() có thể được sử dụng, nhưng điều đó liên quan đến một bản sao phụ.

Lời khuyên của tôi: tiếp tục sử dụng GetBuffer(), nhưng chỉ viết ms.Length bytes, không phải buffer.Length bytes.

Khi bạn đã xóa thêm 0 số không chính xác này, tôi hy vọng bạn sẽ thấy nó hoạt động.

+0

Cảm ơn Marc, tôi nợ bạn một số đồ uống nếu bạn đã từng ở trong khu vực ba bang. Thật buồn cười làm sao những điều đơn giản là khó chịu nhất. – WiredWiz

+0

@WiredWiz bạn vừa nhớ tôi! Tôi đã ở đó khoảng một tuần trước. Nhưng không phải bây giờ, p –

+0

Lời khuyên tuyệt vời, cảm ơn. –

0

Tôi nhận thấy nhà phát triển chính @MarcGravell đã trả lời nhưng tôi chỉ muốn chia sẻ $ 0,02 của chính tôi đã giúp tôi về vấn đề này. Nếu tôi có một byte kích thước cố định [] và nhận được một số byte đọc ngược lại, tôi có thể chỉ định rằng trong khai báo MemoryStream và nó giải quyết vấn đề. Ngoài ra, vì nó áp dụng cho OP, không khai báo MemoryStream cho đến khi bạn đọc xong.

byte[] msg = new byte[4096]; 
int bytesRead = someStreamClass.Read(msg, 0, 4096); 
using (MemoryStream ms = new MemoryStream(msg, 0, bytesRead)) 
{  
    logData = Serializer.Deserialize<LogData>(ms); 
} 

@MarcGravell: Cảm ơn thư viện tuyệt vời này!

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