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.
Related
I have implemented the following method format request body
private async Task<string> FormatRequest(HttpRequest request)
{
request.EnableBuffering();
//Create a new byte[] with the same length as the request stream
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
//Copy the entire request stream into the new buffer
await request.Body.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
//Convert the byte[] into a string using UTF8 encoding
var bodyAsText = Encoding.UTF8.GetString(buffer);
request.Body.Position = 0;
return bodyAsText;
}
I got the following result
------WebKitFormBoundaryY8OPXY2MlrKMjBRe
Content-Disposition: form-data; name="RoleId"
2
------WebKitFormBoundaryY8OPXY2MlrKMjBRe
Content-Disposition: form-data; name="AuthenticationSettingsId"
3
.....
Expected result
"{\"fields\":[\"RoleId\",\"2\",\"AuthenticationSettingsId\",\"1\",\"recommendation\",\"reviewerId\"],\"size\":100,\"filter\":[{\"id\":\"ApplicationId\",\"operator\":\"and\",\"parent\":\"\",\"nested\":false,\"type\":\"integer\",\"value\":[360]}],\"aggregate\":[],\"sort\":[]}"
Note: Previously we used request.EnableRewind() it was returning the above result and later upgraded to .net core 3.0
Here is a high level of how I handle JSON queries. If you really want to get fancy you can implement all this into an abstract class and inherit direct to your data model.
There are plenty of different ways to get where you want to be, hopefully this helps you get there.
I've put comments in the code, but feel free to ask away if something doesn't make sense.
class SomeHttpJsonUtility
{
//If you want to parse your return data
//directly into a data model
class DataModel{
class ReturnData
{
[JsonPropertyName("fields")]
public Field[] Fields { get; set; }
}
class Field
{
[JsonPropertyName("RoleId")]
public int RoleId { get; set; }
//...you get the idea
}
}
//Some data if your sending a post request
private Dictionary<string, string> postParameters = new Dictionary<string, string>();
//Creates a HTTP Client With Specified Parameters
//You can do this any number of ways depending on the
//source you are querying
private HttpClient GetClient()
{
HttpClient _client = new HttpClient();
_client.DefaultRequestHeaders.Clear();
_client.DefaultRequestHeaders.Add(
"UserAgent",
new string[] { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0" });
_client.DefaultRequestHeaders.Add(
"AcceptLanguage",
new string[] { "en-US" });
_client.DefaultRequestHeaders.Add(
"AcceptEncoding",
new string[] { "gzip", "deflate", "br" });
_client.DefaultRequestHeaders.Add(
"Accept",
new string[] { "*/*" });
_client.DefaultRequestHeaders.Add(
"Connection",
new string[] { "keep-alive" });
return _client;
}
private void GetJson(Uri from_uri)
{
//Get the HttpClient With Proper Request Headers
HttpClient _client =
GetClient();
Task.Run(async () =>
{
//If your data comes from a get request
HttpResponseMessage _httpResponse =
await _client.GetAsync(
requestUri:from_uri);
//Or if your response comes from a post
_httpResponse =
await _client.PostAsync(
requestUri: from_uri,
content: new FormUrlEncodedContent(postParameters)
);
//since your initial post used a stream, we can
//keep going in that direction
//Initilize a memory stream to process the data
using(MemoryStream _ms = new MemoryStream())
{
//Send the http response content
////into the memory stream
await _httpResponse.Content.CopyToAsync(
stream: _ms);
//Goto the start of the memory stream
_ms.Seek(
offset: 0,
loc: SeekOrigin.Begin);
//Option 1:
//Send direct to data model
// This is utilizing the Microsoft Library:
// System.Text.Json.Serialization;
DataModel dataModel =
JsonSerializer.Deserialize<DataModel>(
utf8Json: _ms);
//Option 2:
//Send to a string
using(StreamReader _sr = new StreamReader(_ms))
{
string dataAsSting = _sr.ReadToEnd();
}
}
}).Wait();
}
}
If your query is only a Get request, then it's pretty easy get get the exact headers you need.
Using Firefox hit F12 and goto the web address.
Click the Network Tab, then Headers and view the request data.
You really only need a few of these:
Accept
Accept-Encoding
Accept-Language
Connection
User-Agent
Mozilla has some nice resources regarding the different header objects.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept
Host should be taken care of by the HttpClient.
Cookies should be handled by the HttpClient (if you need them)
If you are actually getting the data back as Gzip you'll have to implement a reader, unless the HttpClient you are using will automatically decode it.
And at the end, victory :-)
I think you need to set the content-type on the request when you send it to application/json
Could you try to read this way?
var reader = new System.IO.StreamReader(request.Body);
var body = reader.ReadToEndAsync().Result;
Then you can use Newtonsoft or a similar library on body.
You need to to tokenize / encode your string with some JSON encoder.
Here you have two choices:
the internal (Microsoft) JsonConverter
the Newtonsoft.Json JsonConverter
Karthik, it appears you are sending a multipart request from a webkit browser.
If you would be able to just change it on the client side from multipart to application/json your problem would be fixed.
If this is not possible, you can just use:
private async Task<string> FormatRequest(HttpRequest request)
{
var form = request.Form.ToDictionary(x => x.Key, x => x.Value);
return JsonSerializer.Serialize(form);
}
This could parses your form into a dictionary and returns it as a Json.
(This code is written in dotnet 6, which has System.Text.Json. If you need to stick in .net 3.1, you would need to use a JsonSerializer like Newtonsoft.)
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.
I have written a C# Web API in VS Studio and have created numerous DTO's that get serialized into JSON entities which any client can consume. One of my API calls is to return a PDF file, so after some online research, I set up one of the DTO's is set up in the following format. I read somewhere you can do this, but not 100% sure:
public class MyCustomResult
{
public bool Success;
public DateTime? LastRunDate;
public string ErrorCode;
public string Message;
public ByteArrayContent ReportBody;
}
I do not get any errors when return the object as an IHttpActionResult:
return Ok(result);
I can see on the server that the ByteSize of the report byte[] is approx 700K. However, when I retrieve the object on the client, the JSON entity is approx 400B and no byte content in the ByteContentStream. When I run the query in Postman, I get an empty Header, so it appears that the ByteContentStream can't be serialized by Newtonsoft JSON.
Are there any options I should consider?
Here is a scenario where you'd use ByteArrayContent:
using(var req = new HttpRequestMessage(HttpMethod.Post, new Uri("https://example.com"))
{
req.Content = new ByteArrayContent(...);
using(var resp = await _client.SendAsync(req))
{
var data = await resp.Content.ReadAsAsync<object>();
}
}
What you'd want to do is this:
public class MyCustomResult
{
public bool Success;
public DateTime? LastRunDate;
public string ErrorCode;
public string Message;
public byte[] ReportBody; // <-- change this to byte[]
}
var dataToSend = new MyCustomResult(); // fill this in
using(var req = new HttpRequestMessage(HttpMethod.Post, new Uri("https://example.com"))
{
req.Content = new StringContent(
JsonConvert.SerializeObject(dataToSend, Encoding.UTF8, "application/json"));
using(var resp = await _client.SendAsync(req))
{
var data = await resp.Content.ReadAsAsync<object>();
}
}
(note: this code is not tested)
So what will happen is SerializeObject will convert that byte array into a Base64 string then send it.
The consumer would then have to decode that Base64 string. If it's another Newtonsoft.Json client and the model definitions match, then it will automatically decode it for you.
I understand you are doing an API endpoint. The above examples are to show the use of ByteArrayContent and why it exists in .NET. How you are returning data is correct: return Ok(response); as long as you fix your model.
So to sum it up:
ByteArrayContent is an implementation of HttpContent which is supposed to be used as a response body only. It's not to be used in conjunction with a JSON response.
I have List of objects which contains property of type byte array which is image content. When I send this in JSON format from server to client there is no response body in Internet Explorer browser. If I send around 100 or 1000 rows to client, there is no problem. If I send more then 3000 rows of data there is no response body. Is there any specific method or pattern which I should use to send collection of byte array to client ?
Type:
class Image
{
public byte[] Content { get; set; }
}
MVC:
var obj = new {
rows = Manager.GetImages() *//returns List<Image>*
};
return new JsonResult() {Data = obj, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
the server returns json with collection of type Image to client over http
The HttpWebRequest class has a Chunked property that you can set to true.
https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.sendchunked(v=vs.100).aspx
I know there are a lot of questions about sending HTTP POST requests with C#, but I'm looking for a method that uses WebClient rather than HttpWebRequest. Is this possible? It'd be nice because the WebClient class is so easy to use.
I know I can set the Headers property to have certain headers set, but I don't know if it's possible to actually do a POST from WebClient.
You can use WebClient.UploadData() which uses HTTP POST, i.e.:
using (WebClient wc = new WebClient())
{
byte[] result = wc.UploadData("http://stackoverflow.com", new byte[] { });
}
The payload data that you specify will be transmitted as the POST body of your request.
Alternatively there is WebClient.UploadValues() to upload a name-value collection also via HTTP POST.
You could use Upload method with HTTP 1.0 POST
string postData = Console.ReadLine();
using (System.Net.WebClient wc = new System.Net.WebClient())
{
wc.Headers.Add("Content-Type","application/x-www-form-urlencoded");
// Upload the input string using the HTTP 1.0 POST method.
byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(postData);
byte[] byteResult= wc.UploadData("http://targetwebiste","POST",byteArray);
// Decode and display the result.
Console.WriteLine("\nResult received was {0}",
Encoding.ASCII.GetString(byteResult));
}