C# 通过Web Api中的请求支持Protobuf net

C# 通过Web Api中的请求支持Protobuf net,c#,asp.net-web-api,protobuf-net,C#,Asp.net Web Api,Protobuf Net,我有一个自己创建的web api,只要对象内容类型是application/JSON,我就可以发布JSON对象。我们希望使用移动设备的protobuf将数据发送到web api。如果我将内容类型切换为x-protobuf,并且尽管已将此格式化程序添加到我的WebApiConfig config.Formatters.Add(new ProtoBufFormatter()); 当我使用Chrome扩展“Advanced Rest Client”或Fiddler时,当我执行Get时

我有一个自己创建的web api,只要对象内容类型是
application/JSON
,我就可以发布JSON对象。我们希望使用移动设备的protobuf将数据发送到web api。如果我将内容类型切换为
x-protobuf
,并且尽管已将此格式化程序添加到我的WebApiConfig

        config.Formatters.Add(new ProtoBufFormatter());
当我使用Chrome扩展“Advanced Rest Client”或Fiddler时,当我执行Get时,Web Api似乎会发送一个序列化响应,但当设置为protobuf时,我看不到它接收post请求

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

   [HttpPost]
    public override async Task<LoginResponse> Post([FromBody]LoginRequest request)
    {...}
[HttpPost]
公共重写异步任务Post([FromBody]登录请求请求)
{...}
我还需要什么来确保我的WebApi将对protobuf序列化请求进行反序列化


你需要看什么才能帮上忙?谢谢您的考虑

客户端必须使用protobuf序列化发送请求。高级Rest客户端(或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;

byte[]rawBytes=ProtoBufSerializer.ProtoSerialize(loginRequest);
var client=新的HttpClient();
client.BaseAddress=新Uri(“http://localhost/");
client.DefaultRequestHeaders.Accept.Add(
具有QualityHeaderValue的新媒体类型(“应用程序/x-protobuf”);
var byteArrayContent=新的byteArrayContent(rawBytes);
byteArrayContent.Headers.ContentType=新的MediaTypeHeaderValue(“应用程序/x-protobuf”);
var result=client.PostAsync(“Api/Login”,byteArrayContent).result;

这里是一个原型定义示例,后端和前端代码都带有

原型定义

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;
}

控制器:

[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");
    }
}
[ApiController]
[路线(“[控制器]”)]
公共类PersonController:ControllerBase
{
[HttpGet]
public IActionResult Get()
{
var person=新的人
{
FirstName=“山姆”,
BillingAddress=新地址
{
StreeNumber=“100”,
Street=“某处”,
郊区=“某地”
},
姓氏=“史密斯”
};
var data=person.ToByteArray();
返回文件(数据,“应用程序/八位字节流”);
}
[HttpPost]
公共异步任务Post()
{
var stream=Request.BodyReader.AsStream();
返回文件(流,“应用程序/八位字节流”);
}
[HttpPut]
公共异步任务Put()
{
var stream=Request.BodyReader.AsStream();
var person=person.Parser.ParseFrom(流);
如果(!Request.Headers.ContainsKey(“PersonKey”))抛出新异常(“No key”);
person.PersonKey=Request.Headers[“PersonKey”];
var data=person.ToByteArray();
返回文件(数据,“应用程序/八位字节流”);
}
}

序列化:

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;
    }
}
公共类ProtobufSerializationAdapter:ISerializationAdapter
{
公共字节[]序列化(TRequestBody值,IHeadersCollection请求标头)
{
var message=(IMessage)值作为IMessage;
if(message==null)抛出新异常(“该对象不是Google Protobuf消息”);
返回消息。ToByteArray();
}
public TResponseBody反序列化(字节[]数据,iHeaderCollection responseHeaders)
{
var messageType=typeof(树体);
var parserProperty=messageType.GetProperty(“解析器”);
var parser=parserProperty.GetValue(parserProperty);
var parseFromMethod=parserProperty.PropertyType.GetMethod(“ParseFrom”,新类型[]{typeof(byte[])});
var parsedObject=parseFromMethod.Invoke(解析器,新对象[]{data});
返回(树体)解析对象;
}
}

用法:

          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);
var person=newperson{FirstName=“Bob”,姓氏=“Smith”};
var client=new client(new ProtobufSerializationAdapter(),new Uri(“http://localhost:42908/person"));
person=等待客户。PostAsync(person);