Protobuf-net 和 WebApi,使用哪种格式通过网络返回数据?



我有一个.Net Core 3.1 WebAPI,它:

Serialize
  1. my obj with: ProtoBuf.Serializer.Serialize(stream, 我的对象(;
  2. 返回它:Convert.ToBase64String(stream.GetBuffer((, 0, (int(stream.长度(;

以及调用 WebAPI 和

  1. 从线路获取数据:内存流流 = 新 MemoryStream(Convert.FromBase64String(await 响应。Content.ReadAsStringAsync((((;
  2. 然后将其反序列化回我的 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,以便内容由服务器压缩,而流则不压缩。

最新更新