C# 通过 http 传输序列化 Protobuff 数据的最佳方式
C# Best way to transfer Serialized Protobuff data thru http
我正在使用 Marc Gravell 的 Protobub-Net 来序列化和反序列化对象。
我正在寻找通过 http://
请求传输数据的最有效方式。
这是我到目前为止所做的:
public string ProtobuffToString()
{
Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
List1.Add(2018, 1.2m);
List1.Add(2017, 1.4m);
List1.Add(2016, 1.9m);
using (var stream = new MemoryStream())
{
ProtoBuf.Serializer.Serialize(stream, List1);
return Convert.ToBase64String(stream.ToArray());
}
}
public async System.Threading.Tasks.Task<string> ReadProtobuffAsync()
{
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
using (System.Net.Http.HttpContent content = response.Content)
{
string result = await content.ReadAsStringAsync();
byte[] resultByte = Convert.FromBase64String(result);
using (var stream = new MemoryStream(resultByte))
{
return JsonConvert.SerializeObject(ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(stream));
}
}
}
我可以做得更好吗?
而且是better/faster而不是从json/Json.Net 传输吗?
也许是,因为数据传输会更小,serialization/deserialization更快。
Can i do it better?
Protobuf 是一种二进制序列化格式,针对(反)序列化和 low-footprint 传输进行了优化。通过将数据转换为 Base64,您可以添加另一个转换层并增加传输的占用空间。
And is it better/faster than to transfer it from json/Json.Net?
没有合理的论据可以支持这一说法。重申我之前的声明,Protobuf 是高度优化的,而 JSON 是某种 trade-off,序列化效率不高,可读性也不是很好。
话虽如此,举个小例子,如何通过 HTTP 发送你的 Protobuf
HttpClient client = new HttpClient();
using (var stream = new MemoryStream())
{
// serialize to stream
ProtoBuf.Serializer.Serialize(stream, List1);
stream.Seek(0, SeekOrigin.Begin);
// send data via HTTP
StreamContent streamContent = new StreamContent(stream);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
var response = client.PostAsync("http://what.ever/api/upload", streamContent);
}
如果你想接收 Protobuf,你可以像这样修改你的代码片段
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
using (System.Net.Http.HttpContent content = response.Content)
using (var memoryStream = new MemoryStream())
{
await content.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin); // reset stream
return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(memoryStream); // assuming that you return the Dictionary, not a string
}
实际上我不明白你为什么要 return string
而不是 ReadProtobuffAsync
中的 Dictionary<int, decimal>
。我建议完全放弃 Dictionary
并使用有意义的 protobuf 定义和相应的 类,因为这是 Protobuf 的真正强项。
问题和答案是主观的,完全基于 "best" 的定义。我确实看到了很多不必要的 "extra" 代码。我建议你直接使用Streams,不需要先去内存流或者转换成base64或者转换成json。如果您确实需要字符串表示形式,请在另一个实用程序方法中执行,而不是将其也包装在此代码中。
编写代码
// depending on where you want to write to pass an appropriate Stream like a stream to write directly to an HttpPost or File on disk,
// there is no need to write to memory
public void SerializeToStream(Stream destinationStream)
{
Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
List1.Add(2018, 1.2m);
List1.Add(2017, 1.4m);
List1.Add(2016, 1.9m);
ProtoBuf.Serializer.Serialize(destinationStream, List1);
}
阅读代码
public async System.Threading.Tasks.Task<Dictionary<int, decimal>> ReadProtobuffAsync()
{
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.IO.Stream responseStream = await client.GetStreamAsync("http://localhost:53204/ProtobuffToString"))
{
// deserialize directly from the response stream
return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(responseStream));
}
}
我正在使用 Marc Gravell 的 Protobub-Net 来序列化和反序列化对象。
我正在寻找通过 http://
请求传输数据的最有效方式。
这是我到目前为止所做的:
public string ProtobuffToString()
{
Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
List1.Add(2018, 1.2m);
List1.Add(2017, 1.4m);
List1.Add(2016, 1.9m);
using (var stream = new MemoryStream())
{
ProtoBuf.Serializer.Serialize(stream, List1);
return Convert.ToBase64String(stream.ToArray());
}
}
public async System.Threading.Tasks.Task<string> ReadProtobuffAsync()
{
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
using (System.Net.Http.HttpContent content = response.Content)
{
string result = await content.ReadAsStringAsync();
byte[] resultByte = Convert.FromBase64String(result);
using (var stream = new MemoryStream(resultByte))
{
return JsonConvert.SerializeObject(ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(stream));
}
}
}
我可以做得更好吗?
而且是better/faster而不是从json/Json.Net 传输吗?
也许是,因为数据传输会更小,serialization/deserialization更快。
Can i do it better?
Protobuf 是一种二进制序列化格式,针对(反)序列化和 low-footprint 传输进行了优化。通过将数据转换为 Base64,您可以添加另一个转换层并增加传输的占用空间。
And is it better/faster than to transfer it from json/Json.Net?
没有合理的论据可以支持这一说法。重申我之前的声明,Protobuf 是高度优化的,而 JSON 是某种 trade-off,序列化效率不高,可读性也不是很好。
话虽如此,举个小例子,如何通过 HTTP 发送你的 Protobuf
HttpClient client = new HttpClient();
using (var stream = new MemoryStream())
{
// serialize to stream
ProtoBuf.Serializer.Serialize(stream, List1);
stream.Seek(0, SeekOrigin.Begin);
// send data via HTTP
StreamContent streamContent = new StreamContent(stream);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
var response = client.PostAsync("http://what.ever/api/upload", streamContent);
}
如果你想接收 Protobuf,你可以像这样修改你的代码片段
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
using (System.Net.Http.HttpContent content = response.Content)
using (var memoryStream = new MemoryStream())
{
await content.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin); // reset stream
return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(memoryStream); // assuming that you return the Dictionary, not a string
}
实际上我不明白你为什么要 return string
而不是 ReadProtobuffAsync
中的 Dictionary<int, decimal>
。我建议完全放弃 Dictionary
并使用有意义的 protobuf 定义和相应的 类,因为这是 Protobuf 的真正强项。
问题和答案是主观的,完全基于 "best" 的定义。我确实看到了很多不必要的 "extra" 代码。我建议你直接使用Streams,不需要先去内存流或者转换成base64或者转换成json。如果您确实需要字符串表示形式,请在另一个实用程序方法中执行,而不是将其也包装在此代码中。
编写代码
// depending on where you want to write to pass an appropriate Stream like a stream to write directly to an HttpPost or File on disk,
// there is no need to write to memory
public void SerializeToStream(Stream destinationStream)
{
Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
List1.Add(2018, 1.2m);
List1.Add(2017, 1.4m);
List1.Add(2016, 1.9m);
ProtoBuf.Serializer.Serialize(destinationStream, List1);
}
阅读代码
public async System.Threading.Tasks.Task<Dictionary<int, decimal>> ReadProtobuffAsync()
{
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.IO.Stream responseStream = await client.GetStreamAsync("http://localhost:53204/ProtobuffToString"))
{
// deserialize directly from the response stream
return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(responseStream));
}
}