2013-04-24 4 views
2

Я написал сервер, который использует servicestack, и клиент, который подключается к нему с использованием как JSON, так и protobuf-net (поэтому я уверен, что сервер работает ...). Теперь мне нужно разработать тот же клиент на Windows Mobile с CF3.5, и поскольку servicestack не поддерживается на CF3.5, я использовал на клиенте HttpWebRequest и NewtonSoft.Json.Compact для json-части, таким образом:Protobuf-net с ServiceStack и компактным каркасом

Классы:

[ProtoContract] 
public class ReqPing 
{ 
} 

[ProtoContract] 
public class RespPing 
{ 
    [ProtoMember(1)] 
    public string Result { get; set; } 
} 

Функция:

ReqPing iReqPing = new ReqPing(); 

string json = JsonConvert.SerializeObject(iReqPing); 

HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.0.87:82/json/syncreply/ReqPing"); 
req.ContentType = "text/json"; 
req.Method = "POST"; 
req.ContentLength = json.Length; 

      using (var streamWriter = new StreamWriter(req.GetRequestStream())) 
      { 
       streamWriter.Write(json); 
       streamWriter.Flush(); 
       streamWriter.Close(); 
      } 

      HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); 

      Stream respStream = resp.GetResponseStream(); 

      string resps; 

      using (var reader = new StreamReader(respStream, Encoding.UTF8)) 
      { 
       resps = reader.ReadToEnd();     
      } 

      respStream.Close(); 

      JsonTextReader jreader = new JsonTextReader(new StringReader(resps)); 
      JsonSerializer serializer = new JsonSerializer(); 
      RespPing iRespPing = serializer.Deserialize<RespPing>(jreader); 

и это работает, так что теперь я пытаюсь реализовать то же самое с Protobuf, и я застрял здесь:

ReqPing iReqPing = new ReqPing(); 


var ms = new MemoryStream();?????? correct way? 

Serializer.Serialize<ReqPing>(ms, iReqPing); 

HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.0.87:82/x-protobuf/reply/ReqPing"); 
      req.ContentType = "application/x-protobuf"; 
      req.Method = "POST"; 
      req.ContentLength = ???????? 

how can I write the serialized stream to req??    

      HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); 

      Stream respStream = resp.GetResponseStream(); 

      RespPing iRespPing = Serializer.Deserialize<RespPing>(respStream); 

Любой может предложить мне, как правильно?

Спасибо! Маттиа

EDIT:

Ok о том, как использовать этот поток, но мне нужно установить ContentLength также, или я получаю сообщение об ошибке на GetRequestStream (говорят, что я должен установить ContentLength ...). Я сделал это работать:

byte[] data; 
     using(var stream = new MemoryStream()) 
     { 
      Serializer.Serialize(stream, iReqPing); 
      data = stream.ToArray(); 
      req.ContentLength = data.Length; 
     } 

     using(var stream = req.GetRequestStream()) 
     { 
      stream.Write(data, 0, data.Length);     
     } 

Есть еще один очевидный способ, которым я не хватает?

Другой вопрос: Я заработал, но после двух запросов, на третьем таймаутах в GetRequestStream. Я заметил, что забыл в своем предыдущем звонке позвонить в Close() в свой HttpWebResponse, я исправил его и теперь работает. Странно то, что я забыл закрыть HttpWebResponse даже с моей версией JSON, и там у меня не было проблем ... рутина точно такая же .. можете ли вы угадать причину? Еще раз спасибо!

+0

Я смущен - вы говорите о сериализации, но вызываете десериализацию. Вы пытаетесь прочитать здесь? Или написать? –

+0

iReqPing - мой запрос, и я полагаю, что я должен Сериализовать его, чтобы отправить его с помощью HttpWebRequest. После этого я получаю поток ответов и пытаюсь десериализовать его в моем объекте ответа iRespPing. Я пытаюсь следовать той же схеме, которую я использовал для предыдущего примера JSON, bu хочет сериализоваться с protobuf вместо JSON. –

ответ

1

Как я могу написать сериализованный поток для req ??

using(var stream = req.GetRequestStream()) { 
    Serializer.Serialize(stream, iReqPing); 
} 

, а затем десериализации, как вы уже правильно:

RespPing iRespPing; 
using(var stream = resp.GetResponseStream()) { 
    iRespPing = Serializer.Deserialize<RespPing>(respStream); 
} 

Нет необходимости для MemoryStream, если вы специально не хотите отправить длину вручную. Если вы сделать хотите буфера, то возможно:

byte[] data; 
using(var stream = new MemoryStream()) { 
    Serializer.Serialize(stream, iReqPing); 
    data = stream.ToArray(); 
} 
... 
using(var stream = req.GetRequestStream()) { 
    stream.Write(data, 0, data.Length); 
} 

Редактировать, чтобы показать более эффективное использование MemoryStream повторно теперь уже отредактированный вопрос:

byte[] data; 
    int len; 
    using(var stream = new MemoryStream()) 
    { 
     Serializer.Serialize(stream, iReqPing); 
     data = stream.GetBuffer(); // note this is oversized! 
     len = (int)stream.Length; 
    } 
    req.ContentLength = len; 

    using(var stream = req.GetRequestStream()) 
    { 
     stream.Write(data, 0, len); 
    } 

Тонкость здесь является то, что мы избегали дублирования буфера MemoryStream. Вместо этого мы получаем обратный буфер с негативным размером (вспомним, сколько из них фактически данных), а затем напишите только то, что много байтов.Таким образом, data.Length может быть (в качестве примера) 4096, но len может быть 3012. Это позволяет избежать дополнительного распределения byte[] и Buffer.BlockCopy.

+0

ok для потока, но я получаю: –

+0

@MattiaDurli "a:" ...? –

+0

извините! Я совершенно уверен, что написал весь комментарий ... Интересно, что случилось. Я редактировал вопрос сейчас, спасибо! –

Смежные вопросы