Post byte array to Web API server using HttpClient

I have created this generic and cross platform method to support the BSON format using the Json.NET library so we can reuse it easier later. It works fine in Xamarin platform as well.

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

The method to help to serialise data to BSON format:

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

Then you can use the Post method like this:

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

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

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