使用HttpClient将字节数组发布到Web API服务器

我想将此数据发布到Web API服务器:

public sealed class SomePostRequest { public int Id { get; set; } public byte[] Content { get; set; } } 

将此代码用于服务器:

 [Route("Incoming")] [ValidateModel] public async Task PostIncomingData(SomePostRequest requestData) { // POST logic here } 

这个 – 对于客户:

 var client = new HttpClient(); client.BaseAddress = new Uri("http://localhost:25001/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); var content = new FormUrlEncodedContent(new Dictionary { { "id", "1" }, { "content", "123" } }); var result = await client.PostAsync("api/SomeData/Incoming", content); result.EnsureSuccessStatusCode(); 

一切正常(至少,调试器在PostIncomingData中的断点处停止)。

由于存在byte数组,我不想将其序列化为JSON,并希望将其作为二进制数据发布以减少网络流量(类似于application/octet-stream )。

如何实现这一目标?

我曾尝试使用MultipartFormDataContent ,但看起来我无法理解, MultipartFormDataContent将如何匹配控制器方法的签名。

例如,将内容替换为:

 var content = new MultipartFormDataContent(); content.Add(new FormUrlEncodedContent(new Dictionary { { "id", "1" } })); 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/SomeData/Incoming", content); result.EnsureSuccessStatusCode(); 

导致错误415(“不支持的媒体类型”)。

WebAPI v2.1及更高版本支持开箱即用的BSON(二进制JSON) ,甚至还包含一个MediaTypeFormatter 。 这意味着您可以以二进制格式发布整个邮件。

如果要使用它,则需要在WebApiConfig进行设置:

 public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Formatters.Add(new BsonMediaTypeFormatter()); } } 

现在,您在客户端使用相同的BsonMediaTypeFormatter来序列化您的请求:

 public async Task SendRequestAsync() { var client = new HttpClient { BaseAddress = new Uri("http://www.yourserviceaddress.com"); }; // Set the Accept header for BSON. client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/bson")); var request = new SomePostRequest { Id = 20, Content = new byte[] { 2, 5, 7, 10 } }; // POST using the BSON formatter. MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter(); var result = await client.PostAsync("api/SomeData/Incoming", request, bsonFormatter); result.EnsureSuccessStatusCode(); } 

或者,您可以使用Json.NET将您的类序列化为BSON。 然后,指定您要使用“application / bson”作为“Content-Type”:

 public async Task SendRequestAsync() { using (var stream = new MemoryStream()) using (var bson = new BsonWriter(stream)) { var jsonSerializer = new JsonSerializer(); var request = new SomePostRequest { Id = 20, Content = new byte[] { 2, 5, 7, 10 } }; jsonSerializer.Serialize(bson, request); var client = new HttpClient { BaseAddress = new Uri("http://www.yourservicelocation.com") }; client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/bson")); var byteArrayContent = new ByteArrayContent(stream.ToArray()); byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/bson"); var result = await client.PostAsync( "api/SomeData/Incoming", byteArrayContent); result.EnsureSuccessStatusCode(); } } 

我已经创建了这个通用的跨平台方法来使用Json.NET库来支持BSON格式,以便我们以后可以更轻松地重用它。 它在Xamarin平台上也能正常工作。

 public static async HttpResponseMessage PostBsonAsync(string url, T data) { using (var client = new HttpClient()) { //Specifiy 'Accept' header As BSON: to ask server to return data as BSON format client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/bson")); //Specify 'Content-Type' header: to tell server which format of the data will be posted //Post data will be as Bson format var bSonData = HttpExtensions.SerializeBson(data); var byteArrayContent = new ByteArrayContent(bSonData); byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/bson"); var response = await client.PostAsync(url, byteArrayContent); response.EnsureSuccessStatusCode(); return response; } } 

帮助将数据序列化为BSON格式的方法:

 public static byte[] SerializeBson(T obj) { using (MemoryStream ms = new MemoryStream()) { using (BsonWriter writer = new BsonWriter(ms)) { JsonSerializer serializer = new JsonSerializer(); serializer.Serialize(writer, obj); } return ms.ToArray(); } } 

然后你可以像这样使用Post方法:

 var response = await PostBsonAsync("api/SomeData/Incoming", requestData); 

Fyi,用于protobuf序列化以请求正文post

  LoginRequest loginRequest = new LoginRequest() { Code = "UserId", Password = "myPass", CMToken = "eIFt4lYTKGU:APA91bFZPe3XCDL2r1JUJuEQLlN3FoeFw9ULpw8ljEavNdo9Lc_-Qua4w9pTqdOFLTb92Kf03vyWBqkcvbBfYEno4NQIvp21kN9sldDt40eUOdy0NgMRXf2Asjp6FhOD1Kmubx1Hq7pc", }; byte[] rawBytes = ProtoBufSerializer.ProtoSerialize(loginRequest); var client = new HttpClient(); client.BaseAddress = new Uri("http://localhost:9000/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/x-protobuf")); //var bSonData = HttpExtensions.SerializeBson(data); var byteArrayContent = new ByteArrayContent(rawBytes); byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-protobuf"); var result = client.PostAsync("Api/Login", byteArrayContent).Result; Console.WriteLine(result.IsSuccessStatusCode); 

我将Byte Array转换为Base64 String以发布:

 await client.PostAsJsonAsync( apiUrl, new { message = "", content = Convert.ToBase64String(yourByteArray), } ); 

和接收器可以通过以下方式将byte array转换回Base64 string

 string base64Str = (string)postBody.data; byte[] fileBytes = Convert.FromBase64String(base64Str);