Send JSON list via GET Request - c#

I am attempting to speed up the process of my local software sync. Right now we send a GET requested for each individual record that we need and the API sends back a JSON string containing that records data, which is then inserted into the local database. This all works, however it can be tediously slow. I am trying to speed this up, and was hoping a good way to do so would be to send a JSON of List<Dictionary<string, string>>. This would make it so that I can request much more data in one shot on the API side, add it to the list, and pass it back as JSON to the local machine.
Right now on the local side I have:
Encoding enc = System.Text.Encoding.GetEncoding(1252);
using (HttpClient client = new HttpClient())
{
string basicAuth = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", usr, pwd)));
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", basicAuth);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
string requested = JsonConvert.SerializeObject(tableList);
HttpResponseMessage response = client.GetAsync(syncUrl + hash + "/" + requested).Result;
if (!response.IsSuccessStatusCode)
{
// get the error
StreamReader errorStream = new StreamReader(response.Content.ReadAsStreamAsync().Result, enc);
throw new Exception(errorStream.ReadToEnd());
}
}
My Controller call looks like this:
[System.Web.Http.AcceptVerbs("GET")]
[Route("getRecords/{hash}/{requested}")]
public HttpResponseMessage getRecords(string hash, string requested)
Whenever I make this call it gives me an error that it cannot find the URI and I don't even hit my breakpoint on my API. How do I get this to work, or is there a better way to accomplish what I'm doing?

You need to urlencode the data, if there is any special url chars (like ampersand or slash) it will render unusable the data, so you must urlencode it to be rightly formatted.
Use something like...
string requested = Uri.EscapeDataString(JsonConvert.SerializeObject(tableList));
This will encode the special chars so them can be transferred securely on the URL.

Related

badrequest when sending json data

I'm trying to send json data to an api and it doesn't come trough.
First of all the data is a list of objects. the very first time it works, and that is because the array is empty.
however the second time it tries to send I directly get a 400 without my debugger even coming in the controller.
I suspect that my json data cannot be deserialized form some reason, this is also my second suspect again since my reponse is of type application/problem+json.
However everything might be possible tough.
I have tried to use ['frombody'], I have tried build in json serializer aswell as newtonsoft. I have tried to use formatting.Intended but all witouth luck.
There is one paramater in my object a string that could cause problems as it contains lot of special characters-> this paramater hold a fysical path to a directory so it will contains '/' and '' and space and or other special characters from the directory name.
client:
using (HttpClient client = new HttpClient())
{
var message = new HttpRequestMessage();
message.Content = JsonContent.Create(files, typeof(List<WatchedFile>));
message.RequestUri = new Uri("http://localhost:5245/api/fileagent");
message.Method = HttpMethod.Post;
var response = await client.SendAsync(message);
if (!response.IsSuccessStatusCode)
{
logger.LogError($"Sending to api was not successful {(int)response.StatusCode}");
}
}
This still needs to be refactored to inject the hhtpclient rather thatn the using statement
controller:
[HttpPost]
public async Task<ActionResult> AddMessages([FromBody]List<WatchedFile> messages)
{
messages.ForEach(x => x.Ipaddress = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString());
//send to repository
await context.WatchedFiles.AddRangeAsync(messages);
await context.SaveChangesAsync();
return Ok();
}
I would make sure the JSON is actually a valid JSON.
Then you try to send it with Postman to your endpoint to see if you get the intended result.
That would at least help you eliminate some of the places where it could go wrong.

How do I prevent C# HttpClient from converting %2D to dash in querystring when GET request is executed?

C#, Framework 4.5
RestSharp 105.2.3 (version works on framework 4.5)
I am sending a GET request to an api, with a querystring that has hex value %2D for dashes. The api will not accept dashes, it must be formatted with %2D. Both the Uri create and the GET request through either the C# HttpClient or RestSharp converts the %2D into a dash when the request is executed. Does anyone know of a setting or property that will prevent the request from converting to a dash?
//this is a mock of the initial value
var httpUrl = "https://theapiendpointwithhex.com/api/order?orderid=bee3d72e%2D8170%2D4bad%2Dba95632b09de42ad"
//creating a new Uri
Uri rsUri = new Uri(httpUrl);
//if you view the querytring, it has converted the 2D to dash:
string httpUrlQuery = rsUri.Query;
//httpUrlQuery is ?orderid=bee3d72e-8170-4bad-ba95632b09de42ad
Even if I correct it or use the original in the httpClient request, it converts it to dashes.
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://theapiendpointwithhex.com");
var result = client.GetAsync("/api/order?orderid=bee3d72e%2D8170%2D4bad%2Dba95632b09de42ad").Result;
var testContent = result.Content.ReadAsStringAsync().Result;
the raw request I can see in fiddler is
GET https://theapiendpointwithhex.com/api/order?orderid=bee3d72e-8170-4bad-ba95632b09de42ad
If I change the dashes to %2D in fiddler and re-issue the request, it returns success
The same thing happens if I try another library such as RestSharp
AND it happens if I add the querystring as a parameter in restsharp such as
RestClient rsClient = new RestClient(hostAndPath);
RestRequest rsRequest = new RestRequest(Method.GET);
rsRequest.AddQueryParameter("orderid","bee3d72e%2D8170%2D4bad%2Dba95632b09de42ad"); //converts this to dashes in request
var restResponse = rsClient.Execute(rsRequest);

C# How to put curly brackets in URL

I've been trying to get the data that I need from Facebook's graph api explorer but unfortunately, cant pass the fields necessary in URL via C#.
Here's what I've tried so far
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://graph.facebook.com");
HttpResponseMessage response = client.GetAsync($"cocacola?fields=posts{id,created_time,permalink_url,message,link,type,full_picture}&access_token={textBox1.Text}").Result;
response.EnsureSuccessStatusCode();
string result = response.Content.ReadAsStringAsync().Result;
var jsonRes = JsonConvert.DeserializeObject<dynamic>(result);
var returned = jsonRes.ToString();
MessageBox.Show(returned);
}
What's needed to be done here for fetching data via API? :)
As it turns out, there is an issue because you're using string interpolation and also want curly braces in your string. You'll have to escape them by doubling them.
HttpResponseMessage response = client.GetAsync($"cocacola?fields=posts{{id,created_time,permalink_url,message,link,type,full_picture}}&access_token={textBox1.Text}").Result;
Your approach is incorrect Because Those Variables You Are Trying To Add In Url Are Actually Getting On String, You must escape them to get their valueTherefore Change
HttpResponseMessage response = client.GetAsync($"cocacola?fields=posts{id,created_time,permalink_url,message,link,type,full_picture}&access_token={textBox1.Text}").Result;
To
HttpResponseMessage response = client.GetAsync($"cocacola?fields="+posts{id,created_time,permalink_url,message,link,type,full_picture}+"&access_token="+{textBox1.Text}).Result;
But here to its incorrect cause i dont think {textBox1.Text} and posts{id,created_time,permalink_url,message,link,type,full_picture} Means Anything

Get raw querystring of WebClient in C#

I'm using a WebClient to make a POST request with a query string but I can't see the raw string. This is what I have:
WebClient TheWebClient = new WebClient();
TheWebClient.QueryString.Add("Param1", "1234");
TheWebClient.QueryString.Add("Param2", "4567");
TheWebClient.QueryString.Add("Param3", "4539");
var TheResponse = TheWebClient.UploadValues("https://www.example.com/posturl", "POST", TheWebClient.QueryString);
string TheResponseString = TheWebClient.Encoding.GetString(TheResponse);
//problem is that this only shows the keys
var RawQueryString = TheWebClient.QueryString;
How can I see the actual raw query string?
WebClient.UploadValues doesn't save the request "raw query string" simply because you provided it with them, and it's not gonna change, thus is redundant.
Furthermore, HttpPost requests doesn't use query string for the request payload, it has a url, a message payload; which is appended after the headers, maybe query string. Thus there is nothing new the client class should let you know, so it won't save it.

Softlayer Object Storage ETag MD5 Checksum Calculation

I'm trying to figure out how to calculate the correct checksum when passing data to the Softlayer Object Storage.
I know the ETag is the issue because if I remove it form the request it works, however I'd prefer to use it to verify the uploads are not corrupt.
This is my method:
public bool SaveFile(byte[] file, eFetchStorageContainers container, string internalFileName, string fileName = "", bool overPublicNetwork = false)
{
Authenticate(overPublicNetwork);
client = new RestClient(storage_url);
var resourcePath = string.Format("/{0}/{1}", container, internalFileName);
var req = new RestRequest(resourcePath, RestSharp.Method.PUT);
req.AddHeader("X-Auth-Token", auth_token);
req.AddFile(internalFileName, file, fileName);
var md5Checksum = BitConverter.ToString(MD5.Create().ComputeHash(file)).Replace("-", string.Empty).ToLower();
req.AddHeader("ETag", md5Checksum);
var resp = client.Execute(req);
return false;
}
Here is how the ETag is defined:
I believe the problem lies in the fact that i'm getting the checksum for the file and not the request body.
I want to verify that I should be getting the checksum of the Request Body and NOT the file alone.
If the above is true I'm not even sure how to get the checksum for the body - would love some guidance...
Well I did not use C#, but it works using curl fine for me. I get the checksum for the file and it is working fine.
just in case here some examples about this https://community.runabove.com/kb/en/object-storage/how-to-check-file-consistency-using-etag-and-md5.html
Make sure that your request is similar to examples of the link above.
This is the curl I used:
curl -X PUT -T "C:\Users\ncabero\Downloads\picture.jpg" -H "X-Auth-Token: AUTH_XXXXXXX" -H "Etag: a43bf68dd35599a7873c12128f71b1f4" https://dal05.objectstorage.softlayer.net/v1/AUTH_d684780d-aafe-4772-bcbb-0f07d5f6edf3/rcvtest/picture.jpg
I actually figured this out, I was using RestSharp however its impossible to get the request body.
I moved over to HttpClient and was able to access the request body to create a checksum.
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("X-Auth-Token", auth_token);
var bytes = new ByteArrayContent(file);
var formData = new MultipartFormDataContent();
formData.Add(bytes, internalFileName, internalFileName);
// this creates a checksum to send over for verification of non corrupted transfers
// this is also prevents us from using RestSharp due to its inability to create a checksum of the request body prior to sending
var md5Checksum = BitConverter.ToString(MD5.Create().ComputeHash(formData.ReadAsByteArrayAsync().Result)).Replace("-", string.Empty).ToLower();
httpClient.DefaultRequestHeaders.Add("ETag", md5Checksum);
var url = string.Format("{0}/{1}{2}/{3}", storage_url, containerName, folderId, internalFileName);
var resp = httpClient.PutAsync(url, formData).Result;
httpClient.Dispose();

Categories

Resources