【问题标题】:Support for Protobuf-net with requests in Web Api通过 Web Api 中的请求支持 Protobuf-net
【发布时间】:2017-08-16 14:04:09
【问题描述】:

我有一个我创建的 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 序列化请求。

你需要看什么来帮助?请并感谢您的考虑。

【问题讨论】:

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


    【解决方案1】:

    客户端必须使用 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;
    
    

    【讨论】:

      【解决方案2】:

      这是一个带有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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-16
        • 2017-07-03
        • 2015-10-05
        • 2013-06-24
        • 2018-09-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多