Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post byte array to Web API server using HttpClient

I want to post this data to Web API server:

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

Using this code for server:

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

and this - for client:

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(); 

everything works fine (at least, debugger stops at breakpoint in PostIncomingData).

Since there is a byte array, I don't want to serialize it as JSON, and want to post it as binary data to decrease network traffic (something like application/octet-stream).

How this can be achieved?

I've tried to play with MultipartFormDataContent, but looks like I just can't understand, how MultipartFormDataContent will match signature of controller's method.

E.g., replacing content to this:

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(); 

leads to error 415 ("Unsupported media type").

like image 825
Dennis Avatar asked Aug 24 '15 14:08

Dennis


2 Answers

WebAPI v2.1 and beyond supports BSON (Binary JSON) out of the box, and even has a MediaTypeFormatter included for it. This means you can post your entire message in binary format.

If you want to use it, you'll need to set it in WebApiConfig:

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

Now, you an use the same BsonMediaTypeFormatter at the client side to serialize your request:

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

Or, you can use Json.NET to serialize your class to BSON. Then, specify you want to use "application/bson" as your "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();     } } 
like image 93
Yuval Itzchakov Avatar answered Sep 22 '22 10:09

Yuval Itzchakov


I convert Byte Array into Base64 String to post:

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

and receiver can convert the Base64 String back to Byte Array by:

string base64Str = (string)postBody.content; byte[] fileBytes = Convert.FromBase64String(base64Str); 
like image 32
yu yang Jian Avatar answered Sep 24 '22 10:09

yu yang Jian