C# Get Byte Array from HTTPResposeMessage - c#

I have an API that returns a PDF file as a byte array:
HttpResponseMessage fileResponse = new HttpResponseMessage
{
Content = new ByteArrayContent(report) //here the byte array is >80000 in length
};
fileResponse.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
return fileResponse;
On the client, I have:
HttpResponseMessage result = null;
using (HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
{
result = await client.GetAsync(getFileURL);
}
Byte[] bytes = response.Content.ReadAsByteArrayAsync().Result;
This code worked until an upgrade to .Net 5.
Now bytes is only <350 in length. I have tried converting it from a base64 string as I have read in other solutions, but that throws an error saying it is not a valid base64 string:
string base = response.Content.ReadAsStringAsync().Result.Replace("\"", string.Empty);
byte[] byte = Convert.FromBase64String(base);
Here's what base looks like after the replace, which the next line says is not a valid base64 string. Looks like json but no byte array:
{version:{major:1,minor:1,build:-1,revision:-1,majorRevision:-1,minorRevision:-1},content:{headers:[{key:Content-Type,value:[application/pdf]}]},statusCode:200,reasonPhrase:OK,headers:[],trailingHeaders:[],requestMessage:null,isSuccessStatusCode:true}
So any ideas on how to get the byte array out the response?

The solution I got to work was instead of having the API return an HttpResponseMessage, have it return the byte array directly.
Then in the client converting it from a base64 string gave me the correct byte array that I was able to write as the PDF.

Related

How to send binary data over http, the right way?

I have the following code in C# that converts a string from one encoding to the other and send the response over http.
Everything in the code works fine. I'm just a bit confused 👇
When I return this over http it gets converted into a text representation. I thought this would just send the raw byte array?
Why is it converted? Should I never try and send a raw byte array or is there a case for that when communicating over http? Or is a text representation and a application/octet-stream the way to send binary data over http?
byte[] fromBytes = fromEncoding.GetBytes(body);
byte[] toBytes = Encoding.Convert(fromEncoding, toEncoding, fromBytes);
var response = req.CreateResponse(HttpStatusCode.OK);
MemoryStream ms = new MemoryStream(toBytes);
response.Content = new StreamContent(ms);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return response;

UTF-8 URL Encode

I am having issues in encoding my query params using HttpUtility.UrlEncode() it is not getting converted to UTF-8.
query["agent"] = HttpUtility.UrlEncode("{\"mbox\":\"mailto: UserName#company.com\"}");
I tried using the overload method and passed utf encoding but still it is not working.
expected result:
?agent=%7B%22mbox%22%3A%22mailto%3AUserName%40company.com%22%7D
Actual Result:
?agent=%257b%2522mbox%2522%253a%2522mailto%253aUserName%2540company.com%2522%257d
public StatementService(HttpClient client, IConfiguration conf)
{
configuration = conf;
var BaseAddress = "https://someurl.com/statements?";
client.BaseAddress = new Uri(BaseAddress);
client.DefaultRequestHeaders.Add("Custom-Header",
"customheadervalue");
Client = client;
}
public async Task<Object> GetStatements(){
var query = HttpUtility.ParseQueryString(Client.BaseAddress.Query);
query["agent"] = HttpUtility.UrlEncode( "{\"mbox\":\"mailto:UserName#company.com\"}");
var longuri = new Uri(Client.BaseAddress + query.ToString());
var response = await Client.GetAsync(longuri);
response.EnsureSuccessStatusCode();
using var responseStream = await response.Content.ReadAsStreamAsync();
dynamic statement = JsonSerializer.DeserializeAsync<object>(responseStream);
//Convert stream reader to string
StreamReader JsonStream = new StreamReader(statement);
string JsonString = JsonStream.ReadToEnd();
//convert Json String to Object.
JObject JsonLinq = JObject.Parse(JsonString);
// Linq to Json
dynamic res = JsonLinq["statements"][0].Select(res => res).FirstOrDefault();
return await res;
}
The method HttpUtility.ParseQueryString internally returns a HttpValueCollection. HttpValueCollection.ToString() already performs url encoding, so you don't need to do that yourself. If you do it yourself, it is performed twice and you get the wrong result that you see.
I don't see the relation to UTF-8. The value you use ({"mbox":"mailto: UserName#company.com"}) doesn't contain any characters that would look different in UTF-8.
References:
HttpValueCollection and NameValueCollection
ParseQueryString source
HttpValueCollection source
I strongly suggest you this other approach, using Uri.EscapeDataString method. This method is inside System.Net instead of System.Web that is a heavy dll. In addition HttpUtility.UrlEncode encode characters are in uppercase this would be an issue in certain cases while implementing HTTP protocols.
Uri.EscapeDataString("{\"mbox\":\"mailto: UserName#company.com\"}")
"%7B%22mbox%22%3A%22mailto%3A%20UserName%40company.com%22%7D"

Send Bytes From .net desktop application to website

Is there any way to send data (string , files ,,,) In the form of bytes from desktop application to website
You can use the WebClient class to send data in an HTTP request. A string; example:
string url = "http://website.com/MyController/MyAction";
string data = "Something";
string response;
using WebClient client = new WebClient()) {
client.Encoding = Encoding.UTF8;
response = client.UploadString(url, data);
}
Or a byte array; example:
string url = "http://website.com/MyController/MyAction";
byte[] data = { 1, 2, 3 };
byte[] response;
using WebClient client = new WebClient()) {
response = client.UploadData(url, data);
}
In the web application (assuming that you are using MVC and C#) you would have an action method in a controller that gets the data. Example:
public ActionResult MyAction() {
byte[] data = Request.BinaryRead(Request.ContentLength);
// do something with the data
// create a byte array "response" with something to send back
return Content(response, "text/plain");
}
Both a string and a byte array ends up as a byte array when sent, so you would use Encoding.UTF8.GetString(data) to turn the data into the string sent by UploadString.
To return a string for UploadString you would use Encoding.GetBytes(str) to turn a string into bytes.
There are several overloads of those methods that do similar things, that might fit your needs better, but this should get you started.

How to post image as byte array in visual studio webtest

I'm trying to test my web api but I can't post image as byte array. How can I do it? I'm using File Upload Parameter and specify content-type application/octet-stream but I'm getting 415 unsupported media type. How can I post image as byte array ?
Here is my request:
And Form Post Parameter Properties:
Here is my web api post method:
Here is my webtest request log:
Edit:
#nick_w has great answer but I found another way. I generate code from my webtest file. Correct test request should be shown as below:
WebTestRequest request2 = new WebTestRequest("http://url/api/SendStream");
request2.Method = "POST";
request2.Headers.Add(new WebTestRequestHeader("Content-Type", "application/octet-stream"));
request2.QueryStringParameters.Add("JobId", this.Context["JobId"].ToString(), false, false);
FileStream oFileStream = new FileStream("4_e.jpg", FileMode.Open, FileAccess.Read);
byte[] bytes = new byte[oFileStream.Length];
oFileStream.Read(bytes, 0, System.Convert.ToInt32(oFileStream.Length));
oFileStream.Close();
BinaryHttpBody request2Body = new BinaryHttpBody();
request2Body.ContentType = "application/octet-stream";
request2Body.Data = bytes;
request2.Body = request2Body;
request2.SendChunked = true;
request2.Timeout = 10000000;
yield return request2;
request2 = null;
I expect you are having issues binding the stream parameter to a byte array. Based on information found here and in this question, try changing your method to something like:
public async Task<ResponseEntity<SendStreamResponse>> Post([FromUri]int jobId)
{
byte[] stream = await Request.Content.ReadAsByteArrayAsync();
return await SendStreamAsync(jobId, stream);
}

Prevent Encoding when converting to byte Array

I have a controller that is building using a StringBuilder called param to create a string to post to a REST service. The string that is passed is a query string that will get parsed. I'm encoding the values for each pair so that ampersands, doesn't inadvertantly create a new key.
An encoded param string might look like
clientType=MyClient&form_id=webform_client_form_38&referrer=http://mywebsite&company=My+%26+Company
Here is the code I'm using to send to the REST service
byte[] formData = UTF8Encoding.Default.GetBytes(param.ToString());
req.ContentLength = formData.Length;
//Send the request:
using (Stream post = req.GetRequestStream())
{
post.Write(formData, 0, formData.Length);
}
When I debug the REST service the string is always encoded back, adding the ampersand back between My and Company.
Is there another built in method that will convert the string to a byte without encoding the text?
You can't use a HTML Decode function? that will transform back the string to the correct string that you sent.
HttpUtility.HtmlDecode

Categories