在 Web Api 中支持 Protobuf-net 请求
Support for Protobuf-net with requests in Web Api
我有一个我创建的网络 api,只要 object Content-Type 是 application/json
。我们想使用来自移动设备的 protobuf 将数据发送到网络 api。如果我将 Content-type 切换为 x-protobuf
并且尽管已将此格式化程序添加到我的 WebApiConfig
config.Formatters.Add(new ProtoBufFormatter());
当我使用 Chrome 扩展 "Advanced Rest Client" 或 Fiddler 时,Web Api 似乎会在我执行 Get 时发出序列化响应,但我没有看到当设置为 protobuf 时,它会收到 post 请求。
Controller class 的测试方法 header 目前看起来是这样的:
[HttpPost]
public override async Task<LoginResponse> Post([FromBody]LoginRequest request)
{...}
我还需要做什么来确保我的 WebApi 将 de-serialize protobuf-serialized 请求。
你需要看什么帮助?请并感谢您的考虑。
客户端必须使用 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;
这是一个带有原型定义、后端和前端代码的示例 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;
}
控制器:
[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");
}
}
序列化:
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;
}
}
用法:
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);
我有一个我创建的网络 api,只要 object Content-Type 是 application/json
。我们想使用来自移动设备的 protobuf 将数据发送到网络 api。如果我将 Content-type 切换为 x-protobuf
并且尽管已将此格式化程序添加到我的 WebApiConfig
config.Formatters.Add(new ProtoBufFormatter());
当我使用 Chrome 扩展 "Advanced Rest Client" 或 Fiddler 时,Web Api 似乎会在我执行 Get 时发出序列化响应,但我没有看到当设置为 protobuf 时,它会收到 post 请求。
Controller class 的测试方法 header 目前看起来是这样的:
[HttpPost]
public override async Task<LoginResponse> Post([FromBody]LoginRequest request)
{...}
我还需要做什么来确保我的 WebApi 将 de-serialize protobuf-serialized 请求。
你需要看什么帮助?请并感谢您的考虑。
客户端必须使用 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;
这是一个带有原型定义、后端和前端代码的示例 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;
}
控制器:
[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");
}
}
序列化:
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;
}
}
用法:
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);