10

Kennt irgendjemand irgendwelche Probleme bei der Verwendung von ProtoBuf-Net zum Serialisieren/Deserialisieren zwischen dem kompakten Framework und dem vollständigen .Net-Framework? Ich habe eine Klasse namens LogData, die ich unter Compact Framework 3.5 serialisieren, auf einen Server (laufendes .Net Framework 4.0) übertragen, der dann deserialisiert. Manchmal funktioniert es und manchmal löst es den obigen Fehler aus und ich muss es noch auf eine bestimmte Ursache eingrenzen. Ich habe viele Tests mit unterschiedlichen Werten durchgeführt und kann keinen Fehler oder Grund finden, wenn der Fehler auftritt. Ich schließe meine Klassen unten ein (abzüglich der verschiedenen Konstruktoren). Ich habe den Byte-Puffer auf jeder Seite mehrfach betrachtet und muss noch einen Unterschied in den Daten finden, die über die Leitung von einer Seite zur anderen gesendet werden."Ungültiges Feld in Quelldaten: 0" -Fehler bei ProtoBuf-Net und Compact Framework

[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; } 

} 

Hier ist mein Code, der die Serialisierung tut und

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(); 
    }   
    } 

Senden Und dies ist der Code, der die Daten auf dem Server

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

Kann ich den Code sehen, mit dem Sie arbeiten: serialisieren, an den Draht senden, vom Draht lesen, deserialisieren? Meine starke Wette ist, dass Sie versehentlich einen Pufferabstand von 0 in einem Puffer gelassen haben, ohne die zu lesende Länge einzuschränken. –

+0

Ich habe den Post bearbeitet, um den Serialisierungs- und Deserialisierungscode einzuschließen. Ich habe den Verdrahtungscode weggelassen, der die Akzeptanz von Verbindungen und dergleichen regelt. Wenn Sie weitere Details zum Code benötigen, lassen Sie es mich wissen. Vielen Dank, Marc. – WiredWiz

Antwort

13

Einfach liest man: Sie verwenden:

var buffer = ms.GetBuffer(); 

Und dann buffer.Length. Das bedeutet, dass Sie den übergroßen, gepolsterten Puffer verwenden. Wenn Sie das tun, müssen Sie ms.Length verwenden, die Ihnen die tatsächliche Länge mitteilen wird. Alternativ kann ms.ToArray() verwendet werden, aber das beinhaltet eine zusätzliche Kopie.

Mein Rat: GetBuffer() weiter verwenden, aber nur ms.Length Bytes, nicht buffer.Length Bytes schreiben.

Sobald Sie diese zusätzlichen inkorrekten Nullen entfernt haben, erwarte ich, dass Sie finden, dass es funktioniert.

+0

Danke Marc, ich schulde dir ein paar Drinks, wenn du jemals im Tristate-Bereich bist. Es ist lustig, wie die einfachen Dinge am frustrierendsten sind. – WiredWiz

+0

@WiredWiz du hast mich gerade vermisst! Ich war vor ungefähr einer Woche dort. Aber nicht jetzt; p –

+0

Toller Tipp, danke. –

0

Ich weiß, dass der Hauptentwickler @MarcGravell bereits geantwortet hat, aber ich wollte nur meine eigenen $ 0,02 teilen, die mir bei diesem Problem geholfen haben. Wenn ich eine feste Größe byte [] habe und eine Anzahl von gelesenen Bytes zurückbekomme, kann ich das einfach in der MemoryStream-Deklaration angeben und es löst das Problem. Wie auch für das OP gilt, deklarieren Sie den MemoryStream erst, wenn Sie mit dem Lesen fertig sind.

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: Danke für diese großartige Bibliothek!