Post 字节数组到 Web API 服务器使用 HttpClient
Post byte array to Web API server using HttpClient
我想post这个数据到网络API服务器:
public sealed class SomePostRequest
{
public int Id { get; set; }
public byte[] Content { get; set; }
}
将此代码用于服务器:
[Route("Incoming")]
[ValidateModel]
public async Task<IHttpActionResult> 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<string, string>
{
{ "id", "1" },
{ "content", "123" }
});
var result = await client.PostAsync("api/SomeData/Incoming", content);
result.EnsureSuccessStatusCode();
一切正常(至少,调试器在 PostIncomingData
中的断点处停止)。
因为有一个 byte
数组,我不想将它序列化为 JSON,而是想 post 它作为二进制数据以减少网络流量(类似application/octet-stream
).
如何实现?
我试过 MultipartFormDataContent
,但我似乎无法理解 MultipartFormDataContent
如何匹配控制器方法的签名。
例如,将内容替换为:
var content = new MultipartFormDataContent();
content.Add(new FormUrlEncodedContent(new Dictionary<string, string> { { "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 ("Unsupported media type")。
WebAPI v2.1 及更高版本 supports BSON (Binary JSON) out of the box,甚至包含一个 MediaTypeFormatter
。这意味着您可以 post 二进制格式的整个消息。
如果你想使用它,你需要在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 将您的 class 序列化为 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<T>(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<T>(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>(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<SamplePostRequest>("api/SomeData/Incoming", requestData);
仅供参考,用于请求正文帖子的 protobuf 序列化
LoginRequest loginRequest = new LoginRequest()
{
Code = "UserId",
Password = "myPass",
CMToken = "eIFt4lYTKGU:APA91bFZPe3XCDL2r1JUJuEQLlN3FoeFw9ULpw8ljEavNdo9Lc_-Qua4w9pTqdOFLTb92Kf03vyWBqkcvbBfYEno4NQIvp21kN9sldDt40eUOdy0NgMRXf2Asjp6FhOD1Kmubx1Hq7pc",
};
byte[] rawBytes = ProtoBufSerializer.ProtoSerialize<LoginRequest>(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<T>(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
到post:
await client.PostAsJsonAsync( apiUrl,
new {
message = "",
content = Convert.ToBase64String(yourByteArray),
}
);
接收方可以通过以下方式将 Base64 String
转换回 Byte Array
:
string base64Str = (string)postBody.content;
byte[] fileBytes = Convert.FromBase64String(base64Str);
我想post这个数据到网络API服务器:
public sealed class SomePostRequest
{
public int Id { get; set; }
public byte[] Content { get; set; }
}
将此代码用于服务器:
[Route("Incoming")]
[ValidateModel]
public async Task<IHttpActionResult> 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<string, string>
{
{ "id", "1" },
{ "content", "123" }
});
var result = await client.PostAsync("api/SomeData/Incoming", content);
result.EnsureSuccessStatusCode();
一切正常(至少,调试器在 PostIncomingData
中的断点处停止)。
因为有一个 byte
数组,我不想将它序列化为 JSON,而是想 post 它作为二进制数据以减少网络流量(类似application/octet-stream
).
如何实现?
我试过 MultipartFormDataContent
,但我似乎无法理解 MultipartFormDataContent
如何匹配控制器方法的签名。
例如,将内容替换为:
var content = new MultipartFormDataContent();
content.Add(new FormUrlEncodedContent(new Dictionary<string, string> { { "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 ("Unsupported media type")。
WebAPI v2.1 及更高版本 supports BSON (Binary JSON) out of the box,甚至包含一个 MediaTypeFormatter
。这意味着您可以 post 二进制格式的整个消息。
如果你想使用它,你需要在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 将您的 class 序列化为 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<T>(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<T>(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>(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<SamplePostRequest>("api/SomeData/Incoming", requestData);
仅供参考,用于请求正文帖子的 protobuf 序列化
LoginRequest loginRequest = new LoginRequest()
{
Code = "UserId",
Password = "myPass",
CMToken = "eIFt4lYTKGU:APA91bFZPe3XCDL2r1JUJuEQLlN3FoeFw9ULpw8ljEavNdo9Lc_-Qua4w9pTqdOFLTb92Kf03vyWBqkcvbBfYEno4NQIvp21kN9sldDt40eUOdy0NgMRXf2Asjp6FhOD1Kmubx1Hq7pc",
};
byte[] rawBytes = ProtoBufSerializer.ProtoSerialize<LoginRequest>(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<T>(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
到post:
await client.PostAsJsonAsync( apiUrl,
new {
message = "",
content = Convert.ToBase64String(yourByteArray),
}
);
接收方可以通过以下方式将 Base64 String
转换回 Byte Array
:
string base64Str = (string)postBody.content;
byte[] fileBytes = Convert.FromBase64String(base64Str);