10

Qualcuno è a conoscenza di problemi quando si utilizza ProtoBuf-Net per serializzare/deserializzare tra il framework compatto e il framework .Net completo? Ho una classe chiamata LogData che sto serializzando sotto framework compatto 3.5, che trasmette a un server (in esecuzione .Net framework 4.0), che poi deserializza. A volte funziona e talvolta getta l'errore di cui sopra e devo ancora restringerlo a causa specifica. Ho fatto molti test con valori diversi e non riesco a trovare alcuna rima o ragione per quando si verifica l'errore. Sto includendo le mie classi qui sotto (meno i vari costruttori). Ho osservato il buffer di byte su entrambi i lati in più occasioni e devo ancora trovare una differenza tra i dati inviati sul filo da un lato all'altro."Campo non valido nei dati di origine: 0" errore con ProtoBuf-Net e 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; } 

} 

Ecco il mio codice che fa la serializzazione e l'invio

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

E questo è il codice che legge i dati sul 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

Posso vedere il codice che si sta utilizzando per: serializzare, inviare al filo, leggere dal filo, deserializzare? La mia scommessa forte è che hai lasciato accidentalmente qualche padding 0 in un buffer, senza limitare la lunghezza da leggere. –

+0

Ho modificato il post per includere il codice serialize e deserialize. Ho omesso il codice di cablaggio che gestisce la negoziazione dell'accettazione delle connessioni e così via. Se hai bisogno di ulteriori dettagli sul codice fammelo sapere. Grazie mille Marc. – WiredWiz

risposta

13

facile: si utilizza:

var buffer = ms.GetBuffer(); 

E quindi buffer.Length. Ciò significa che stai utilizzando il buffer sovradimensionato e imbottito. Se lo fai devi usare ms.Length, che ti dirà la lunghezza effettiva . In alternativa, è possibile utilizzare ms.ToArray(), ma ciò implica una copia aggiuntiva.

Il mio consiglio: continuare a utilizzare GetBuffer(), ma scrivere solo byte LengthLength, non buffer.Lunghezza byte.

Dopo aver rimosso questi zeri non corretti, mi aspetto che troverete che funziona.

+0

Grazie Marc, ti devo dei drink se ti trovi nella zona dei tre stati. È divertente come le cose semplici siano le più frustranti. – WiredWiz

+0

@WiredWiz ti sei appena perso! Ero lì circa una settimana fa. Ma non ora; p –

+0

Grande consiglio, grazie. –

0

Mi rendo conto che lo sviluppatore principale @MarcGravell ha già risposto ma volevo solo condividere il mio $ 0,02 che mi ha aiutato su questo problema. Se ho un byte di dimensione fissa [] e ottengo un conteggio di byte letti in risposta, posso semplicemente specificarlo nella dichiarazione di MemoryStream e risolve il problema. Inoltre, poiché si applica all'OP, non dichiarare il MemoryStream finché non hai finito di leggere.

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: Grazie per questa fantastica libreria!

Problemi correlati