使用Web Api中的请求支持Protobuf-net

时间:2017-08-16 14:04:10

标签: c# asp.net-web-api protobuf-net

我创建了一个web api,只要对象Content-Type为application/json,就可以发布JSON对象帖子。我们希望使用来自移动设备的protobuf将数据发送到web api。如果我将Content-type切换为x-protobuf,尽管已将此格式化程序添加到我的WebApiConfig

        config.Formatters.Add(new ProtoBufFormatter());

当我使用Chrome扩展程序" Advanced Rest Client"或者Fiddler,看起来Web Api会在我执行Get时发出序列化响应,但是当设置为protobuf时我没有看到它收到post请求。

到目前为止,Controller类的测试方法标题如下所示:

   [HttpPost]
    public override async Task<LoginResponse> Post([FromBody]LoginRequest request)
    {...}

我还需要确保我的WebApi将反序列化protobuf序列化请求。

您需要看到什么帮助?拜托,谢谢你的考虑。

2 个答案:

答案 0 :(得分:3)

客户端必须使用protobuf序列化发送请求。 Advanced Rest Client(或Fiddler)不会序列化对象。我编写了一个测试工具客户端,将对象序列化为

 byte[] rawBytes = ProtoBufSerializer.ProtoSerialize<LoginRequest>(loginRequest);

        var client = new HttpClient();
        client.BaseAddress = new Uri("http://localhost/");
        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/x-protobuf"));

        var byteArrayContent = new ByteArrayContent(rawBytes);
        byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-protobuf");

        var result = client.PostAsync("Api/Login", byteArrayContent).Result;

答案 1 :(得分:0)

以下是带有原型定义,带有RestClient.Net的后端和前端代码的示例。

原始定义

message Person {
  string PersonKey = 1;
  string FirstName = 2;
  string Surname=3;
  Address BillingAddress = 4;
}

message Address {
  string AddressKey = 1;
  string StreeNumber = 2;
  string Street=3;
  string Suburb=4;
}

Code Reference

控制器:

[ApiController]
[Route("[controller]")]
public class PersonController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        var person = new Person
        {
            FirstName = "Sam",
            BillingAddress = new Address
            {
                StreeNumber = "100",
                Street = "Somewhere",
                Suburb = "Sometown"
            },
            Surname = "Smith"
        };

        var data = person.ToByteArray();

        return File(data, "application/octet-stream");
    }

    [HttpPost]
    public async Task<IActionResult> Post()
    {
        var stream = Request.BodyReader.AsStream();
        return File(stream, "application/octet-stream");
    }

    [HttpPut]
    public async Task<IActionResult> Put()
    {
        var stream = Request.BodyReader.AsStream();

        var person = Person.Parser.ParseFrom(stream);

        if (!Request.Headers.ContainsKey("PersonKey")) throw new Exception("No key");

        person.PersonKey = Request.Headers["PersonKey"];

        var data = person.ToByteArray();

        return File(data, "application/octet-stream");
    }
}

Code Reference

序列化:

public class ProtobufSerializationAdapter : ISerializationAdapter
{
    public byte[] Serialize<TRequestBody>(TRequestBody value, IHeadersCollection requestHeaders)
    {
        var message = (IMessage)value as IMessage;           
        if (message == null) throw new Exception("The object is not a Google Protobuf Message");
        return message.ToByteArray();
    }

    public TResponseBody Deserialize<TResponseBody>(byte[] data, IHeadersCollection responseHeaders)
    {
        var messageType = typeof(TResponseBody);
        var parserProperty = messageType.GetProperty("Parser");
        var parser = parserProperty.GetValue(parserProperty);
        var parseFromMethod = parserProperty.PropertyType.GetMethod("ParseFrom", new Type[] { typeof(byte[]) });
        var parsedObject = parseFromMethod.Invoke(parser,new object[] { data });
        return (TResponseBody)parsedObject;
    }
}

Code Reference

用法:

          var person = new Person { FirstName = "Bob", Surname = "Smith" };
          var client = new Client(new ProtobufSerializationAdapter(), new Uri("http://localhost:42908/person"));
          person = await client.PostAsync<Person, Person>(person);

Code Reference