我有一个.Net Core 3.1 WebAPI,它:
Serialize- my obj with: ProtoBuf.Serializer.Serialize(stream, 我的对象(;
- 返回它:Convert.ToBase64String(stream.GetBuffer((, 0, (int(stream.长度(;
以及调用 WebAPI 和
- 从线路获取数据:内存流流 = 新 MemoryStream(Convert.FromBase64String(await 响应。Content.ReadAsStringAsync((((;
- 然后将其反序列化回我的 obj:myobj = ProtoBuf.Serializer.Deserialize(stream(;
一切正常,但我怀疑是否可以对其进行优化并避免转换为 byte[]/base4 字符串并返回。
这是通过线路传输protobuf数据的正确方法,还是可以以更好的方式完成?
如何通过 http 线路发送原始字节:
var binaryContent = new ByteArrayContent(new byte[] { 1, 2, 3 });
binaryContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
content.Add(binaryContent, "content");
var result = await client.PostAsync("api/bytes/incoming", content);
诀窍是接收者必须知道"ContentType:application/octet-stream",这对于大多数Web服务器来说不是默认的。所以服务器端需要更多的努力:
public class RawRequestBodyFormatter : InputFormatter
{
public RawRequestBodyFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));
}
/// <summary>
/// Allow text/plain, application/octet-stream and no content type to
/// be processed
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Boolean CanRead(InputFormatterContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var contentType = context.HttpContext.Request.ContentType;
if (string.IsNullOrEmpty(contentType) || contentType == "text/plain" ||
contentType == "application/octet-stream")
return true;
return false;
}
/// <summary>
/// Handle text/plain or no content type for string results
/// Handle application/octet-stream for byte[] results
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
var contentType = context.HttpContext.Request.ContentType;
if (string.IsNullOrEmpty(contentType) || contentType == "text/plain")
{
using (var reader = new StreamReader(request.Body))
{
var content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}
if (contentType == "application/octet-stream")
{
using (var ms = new MemoryStream(2048))
{
await request.Body.CopyToAsync(ms);
var content = ms.ToArray();
return await InputFormatterResult.SuccessAsync(content);
}
}
return await InputFormatterResult.FailureAsync();
}
}
和启动时.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(o => o.InputFormatters.Insert(0, new RawRequestBodyFormatter()));
}
和控制器
[HttpPost]
[Route("api/bytes/incoming")]
public byte[] RawBytesFormatter([FromBody] byte[] rawData)
{
return rawData;
}
我从 Rick Strahl 的优秀博客文章中获取了服务器端片段:https://weblog.west-wind.com/posts/2017/Sep/14/Accepting-Raw-Request-Body-Content-in-ASPNET-Core-API-Controllers?Page=2
- 所有对他的赞誉都:)
我发现WebAPI可以直接返回ProtoBuf.Serializer.Serialize写入的流。这里的重点不是释放流(让它对 GC 执行(。
客户端可以 ProtoBuf.Serializer.反序列化响应。Content.ReadAsStreamAsync((.
但
我坚持使用 Base64string,以便内容由服务器压缩,而流则不压缩。