带有 ServiceStack 和紧凑框架的 Protobuf-net
Posted
技术标签:
【中文标题】带有 ServiceStack 和紧凑框架的 Protobuf-net【英文标题】:Protobuf-net with ServiceStack and compact framework 【发布时间】:2013-04-24 15:15:24 【问题描述】:我编写了一个使用 servicestack 的服务器,以及一个使用 JSON 和 protobuf-net 连接到它的客户端(所以我确信服务器可以工作......)。 现在我需要使用 CF3.5 在 Windows Mobile 上开发相同的客户端,并且由于 CF3.5 不支持 servicestack,因此我在客户端 HttpWebRequest 和 NewtonSoft.Json.Compact 上使用了 json 部分,这样:
类:
[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);
任何人都可以建议我正确的方法是什么?
谢谢! 马蒂亚
编辑:
好的,关于如何使用流,但我也需要设置 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 中超时。我注意到我在之前的调用中忘记了在我的 HttpWebResponse 中调用 Close(),我更正了它,现在可以工作了。 奇怪的是,即使使用我的 JSON 版本,我也忘记关闭 HttpWebResponse,而且我没有任何问题......例程完全一样......你能猜到原因吗? 再次感谢!
【问题讨论】:
我很困惑 - 你在谈论序列化但调用反序列化。你想在这里阅读吗?还是写? iReqPing 是我的请求,我想我必须对其进行序列化才能使用 HttpWebRequest 发送它。之后,我得到响应流并尝试在我的 iRespPing 响应对象中反序列化它。我尝试遵循与前面的 JSON 示例相同的模式,但希望使用 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
的缓冲区——取而代之的是我们获得了 oversized 后备缓冲区(记住要注意其中有多少是实际数据),然后写入 那么多 个字节。所以data.Length
可以是(例如)4096
,但len
可以是3012
。这避免了额外的byte[]
分配和Buffer.BlockCopy
。
【讨论】:
对不起!我很确定我写了整个评论......我想知道发生了什么。我现在编辑了问题,谢谢! @MattiaDurli 重新编辑您的编辑 - 是的,看起来很正确;你可以让它更高效一些 - 我会编辑来演示以上是关于带有 ServiceStack 和紧凑框架的 Protobuf-net的主要内容,如果未能解决你的问题,请参考以下文章
从 multipart/form-data 接收带有 servicestack 的文件
在 ServiceStack 中,我如何使用外部发布的 JWT
任何人都有使用 ServiceStack 或其他 .Net 服务框架的经验? [关闭]
为啥 UserAuthExtensions.PopulateFromMap(session, jwtPayload) 不能在 ServiceStack.Auth 中正确反序列化带有转义的 json 值