webentwicklung-frage-antwort-db.com.de

Senden Sie ein Byte-Array mit HttpClient an den Web-API-Server

Ich möchte diese Daten auf dem Web-API-Server veröffentlichen:

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

Verwenden Sie diesen Code für den Server:

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

und das - für den Kunden:

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

alles funktioniert gut (zumindest hält der Debugger am Haltepunkt in PostIncomingData). 

Da es ein byte-Array gibt, möchte ich es nicht als JSON serialisieren und es als binäre Daten veröffentlichen, um den Netzwerkverkehr zu verringern (etwa application/octet-stream).

Wie kann das erreicht werden? 

Ich habe versucht, mit MultipartFormDataContent zu spielen, aber ich kann einfach nicht verstehen, wie MultipartFormDataContent mit der Signatur der Controller-Methode übereinstimmt.

Zum Beispiel den Inhalt ersetzen:

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

führt zu Fehler 415 ("Nicht unterstützter Medientyp").

25
Dennis

WebAPI v2.1 und höher unterstützt BSON (Binary JSON) ab Werk und enthält sogar eine MediaTypeFormatter. Das heißt, Sie können Ihre gesamte Nachricht im Binärformat posten.

Wenn Sie es verwenden möchten, müssen Sie es in WebApiConfig setzen:

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

Jetzt können Sie dieselbe BsonMediaTypeFormatter auf der Clientseite verwenden, um Ihre Anfrage zu serialisieren:

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

Oder Sie können Json.NET verwenden, um Ihre Klasse mit BSON zu serialisieren. Geben Sie anschließend an, dass Sie "application/bson" als "Content-Type" verwenden möchten:

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

Ich habe diese generische und plattformübergreifende Methode erstellt, um das BSON-Format mithilfe der Json.NET-Bibliothek zu unterstützen, damit wir es später leichter wiederverwenden können. Es funktioniert auch auf der Xamarin-Plattform.

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

Die Methode zur Serialisierung von Daten im 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();
    }
}

Dann können Sie die Post-Methode folgendermaßen verwenden:

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

Ich wandle Byte Array in Base64 String um: 

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

und der Empfänger kann den byte array zurück in Base64 string konvertieren durch:

string base64Str = (string)postBody.data;
byte[] fileBytes = Convert.FromBase64String(base64Str);
0
yu yang Jian

Fyi, zur Protobuf-Serialisierung, um Body-Posts anzufordern

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