9

I've written my first ASP.NET Core Web API server. The routing is working and it is sending/receiving. I'd like to send a raw Byte array in response to a Get and I'd like to bypass any serialization (as well as any deserialization in my WPF client). For example, in my server:

[HttpGet("api/data")]
public Byte[] GetData()
{
    Byte[] data = new Byte[]{1, 2, 3, 4, 5};
    return data; // No JSON, BSON or anything else...just my array. Is it done this way?
}

In my WPF client I'd like to use the HttpClient class to receive the array - no deserialization required:

// Assume an instantiated and initialized HttpClient object called "httpCLient"
HttpResponseMessage response = httpClient.GetAsync("/api/data").Result;
// Now what?

I've scoured the internet but I haven't found an example of this, and I've been unable to figure out on my own. Could somebody please show me how this is done?

Update: I believe the client-side Byte[] retrieval can be accomplished via "HttpContent.ReadAsByteArrayAsync()" as shown here: Convert HttpContent into byte[]. I still am unsure as to how to send the raw (unserialized) Byte[] from the ASP.NET Core Web API side however.

Tim Sylvester
  • 22,897
  • 2
  • 80
  • 94
LKeene
  • 627
  • 1
  • 8
  • 22
  • Possible duplicate of [Getting content/message from HttpResponseMessage](http://stackoverflow.com/questions/15936180/getting-content-message-from-httpresponsemessage) – Colin Apr 06 '17 at 23:07
  • Thanks Colin. I think at the client side I can retrieve the Byte[] by the following: Byte[] data = httpResponseMessage.Content.ReadAsByteArrayAsync().Result; However, I cannot test this because I'm still unsure of how to send the raw Byte[] from the server. – LKeene Apr 06 '17 at 23:57
  • http://stackoverflow.com/questions/23884182/how-to-get-byte-array-properly-from-an-web-api-method-in-c check Luaan's answer. Use the ByteArrayContent – Marcus Höglund Apr 07 '17 at 06:38
  • Thanks Marcus. Unfortunately Luaan's answer is using the "HttpResponseMessage" class. This type doesn't seem to be supported in .NET Core...at least I can find no mention of it in the docs. – LKeene Apr 07 '17 at 20:49
  • @LKeene You just need to add a refrence to the System.Net.Http [NuGet package](https://www.nuget.org/packages/System.Net.Http/) to get access to it in your ASP.NET core project. – Scott Chamberlain Apr 07 '17 at 21:12
  • Thank you Scott. I've now implemented Luann's approach on the server, sending back a Byte[4000000] via "HttpResponseMessage" object. In my client I'm using "Byte[] values = response.Content.ReadAsByteArrayAsync().Result;" but it only retrieves a byte array 279 elements long. Any idea what the problem may be? I'm really taken aback by the difficulty of this. – LKeene Apr 07 '17 at 22:20

2 Answers2

8

Okay, thanks to the input I'm getting I have the following which does indeed transfer the array with the correct values:

On the server side (ASP.NET Core web api):

[HttpGet("/api/data")]
public async Task GetData()
{
    await Response.Body.WriteAsync(myByteArray, 0, myByteArray.Length);
}

On the WPF client I have:

HttpResponseMessage response = httpClient.GetAsync("/api/data").Result;
Byte[] data = response.Content.ReadAsByteArrayAsync().Result;

Frankly I don't understand how this is working (what is "Response.Body.WriteAsync...") and I don't like to blindly use code that "just works so move on". Can someone please explain how this is working, or even if this is the correct approach?

Also, is this actually bypassing serialization/deserialization? I ask because when both client and server are running on the same machine (localhost) it's taking approx. 75ms to retrieve a byte[] of length 4,194,304...that's only around 4MB and seems pretty slow for just a raw transfer of bytes.

Austin Salgat
  • 416
  • 5
  • 13
LKeene
  • 627
  • 1
  • 8
  • 22
  • 2
    How do you do the opposite: Post a raw byte array to the server? – Shimmy Weitzhandler Nov 18 '17 at 22:38
  • Yes, this is bypassing serialization. `Response.Body.WriteAsync` is the same thing that the framework eventually calls with serialized data when you use the normal pattern of returning `ActionResult` objects. It's probably slow because you're running debug versions in a debugger? – Tim Sylvester Apr 19 '19 at 01:41
  • One thing that needs fixing is changing "async void" to "async Task". – Austin Salgat Nov 04 '19 at 16:22
-2

You could send the byte array in a JSON object. I'm not exactly sure what you are asking, but if you are looking for some form of duplex communication, I would look into SignalR.

If you want to consume the API you are writing from multiple types of systems, I would suggest packing the byte array in a JSON object for interoperability.

I hope that answered your question!

Colin
  • 624
  • 8
  • 27
  • Sorry, I just noticed your comment in the code that says no JSON! – Colin Apr 07 '17 at 06:28
  • Eeewwww.. Byte array in JSON!? Oh wait.. BSON. Doh! ahhaha - you missed the point, OP is struggling to return raw bytes. Just having a return type of byte[] Base64Encodes the result.. and in my case serialiser the enitre http response msg. doh! – Piotr Kula Apr 17 '18 at 21:33
  • Okay, what about when you're consuming it with a JavaScript client and you want everything formatted the same way? I only say JSON because I write my APIs to always return in some standard format. – Colin Apr 19 '18 at 00:48
  • But I see your point, I misunderstood the OP, I'm just saying that I write my web back end to communicate in JSON for my JS front end. – Colin Apr 19 '18 at 00:49
  • Yea that is fair enough, I also do that. But the reason I landed on this question is because I wanted to return raw bytes because the client expects this, for example some clients want XML and others want TLV Wire Protocols, etc etc. It is not very obvious on how to override all the fancy serialiser stuff in Core to just dump the bytes without doing any "middleware" Base64, XML/JSON parsing.. just.. gimme.. da.. bytes! :D – Piotr Kula Apr 24 '18 at 08:01