Using http client to send header and content via post - c#

I'm making a really simple call to an API to receive some data. I need to send headers to get authorized also I need to send some content on the body. This is what I came up with :
public async Task<List<LoremIpsum>> LoremIpsumJson()
{
LoremIpsum1 data = null;
try
{
var client = new HttpClient();
//now lets add headers . 1.method, 2.token
client.DefaultRequestHeaders.Add("Method", "LoremIpsumExample");
client.DefaultRequestHeaders.Add("Token", "sometoken");
HttpContent content = new StringContent("{\"Name\":\"John\",\"Surname\":\"Doe\",\"Example\":\"SomeNumber\"}", Encoding.UTF8, "application/json");
// ==edit==
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsync("www.theUrlToTheApi", content);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
data = JsonConvert.DeserializeObject<QueueInfo>(json);
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message.ToString());
}
return data.data;
Debug.WriteLine(data.data);
}
The app breaks after response.EnsureSuccessStatusCode(); because the request obviously is not successful.
I think I'm really missing something really simple here. How can I do this call?
The error is
StatusCode: 406, ReasonPhrase: 'Not Acceptable'

There could be many reasons for this not working. For instance: keyvalues.ToString() is most likely not putting in the value you want. Seems like you might need to serialize to json rather than just calling .ToString().
Use a tool like postman first and get it working there so you have a working example then try and recreate in C#. It will make your life a lot easier.

For everyone coming here to find a solution.
HttpContent cannot take a header much o less a content-type. There was a typo on adding the content-type which was supposed to be added in HttpClient in this way:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

Related

GET Request return 400 bad response

It's a generic question, but I need help with my specific case.
I have a simple GET endpoint (see image) which I've tested with Postman and it works
It takes two id tokens in the header and thats it.
I've put breakpoints in the code and copied the exact instance of the ids into Postman and the request works, but executing from code, I get a 400 response
using (HttpClient client = new HttpClient())
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://*******.execute-api.ap-southeast-2.amazonaws.com/dev/uploads/image.jpg"),
Method = HttpMethod.Get,
};
var idToken = Application.Current.Properties["id_token"].ToString();
var accessToken = Application.Current.Properties["access_token"].ToString();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Add("Id-Token", idToken);
request.Headers.Add("Access-Token", accessToken);
var response = await client.SendAsync(request);
}
I've tried with and without the content-type header and makes no difference. Also doesn't matter if it's present in Postman
This is a Xamarin project which is where Application.Current.Properties comes from. I'm utilising other endpoints in the application are there are no issues with accessing the tokens like this.

Is there a way to parameterize the HTTP method when using System.Net.Http.HttpClient?

I'm using HttpClient in .Net core 3.1. Most of my requests follow a similar pattern regardless of the HTTP method used:
build URL
build (optional) JSON payload
send request
await response
check status code
parse (optional) JSON response
so I've built a wrapper function that does all these things, and it takes the HTTP method as a parameter. However, when it comes to the "send request" step, I need to use a switch statement to invoke the appropriate method on HttpClient to invoke.
I'm sure that under the skin, get GetAsync() PostAsync() etc. are calling the same underlying function and passing the Http method as a parameter. but I can't see any way of calling it like this from the outside. It seems a strange omission as in my experience most HTTP libraries work that way.
Hope this will help you.
// For JsonConvert use Newtonsoft.Json
string url = "YourURL";
string body = JsonConvert.SerializeObject(BodyModel);
string headerParameter = "ASD123456789";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Content-Type of request, it can be application/xml to other
client.DefaultRequestHeaders.Add("Device", headerParameter ); // first is name, second one is value
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url) // there you can have Get, Post, Put, Delete and etc. And every request needs to be configured by its settings
{
Content = new StringContent(body, Encoding.UTF8, "application/json")
};
HttpResponseMessage response = await client.SendAsync(request);
if ((int)response.StatusCode == 200)
{
string responseString = await response.Content.ReadAsStringAsync();
ResponseModel responseModel = JsonConvert.DeserializeObject<ResponseModel>(responseString);
}

"Pass through" controller action (gets and returns JSON) in .NET Core 3.1

Someone's probably done this before but I can't seem to formulate the question properly to find results. I want to make AJAX calls from a view, but I can't directly call the external API from javascript because there's a key that I can't expose. My idea is to have another controller action that I call from the page that calls the actual external REST API I want to get data from and just passes it on as a JSON. I see lots of examples of getting a JSON through C# and deserializing it but not many where you get a JSON and then return it and consume it from the view. Any help appreciated.
public JsonResult GetStuff()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("Stuff/?Id=" + id).Result;
*code to take response and pass it on as a JSON that I can consume from Javascript
}
Here is what I recommend.
[HttpGet("myapi/{id}");
public async Task MyApi(int id) {
// Replace these lines as needed to make your API call properly.
using HttpClient client = new() {
BaseAddress = REMOTE_SERVER_BASE
}
// Make sure to properly encode url parameters if needed
using HttpResponseMessage response = await client.GetAsync($"myapi/{id}");
this.HttpContext.Response.StatusCode = (int)response.StatusCode;
foreach (KeyValuePair<string, IEnumerable<string>> header in response.Headers) {
this.HttpContext.Response.Headers[header.Key] = new StringValues(header.Value.ToArray());
}
await response.Content.CopyToAsync(this.HttpContext.Response.Body);
}
This will copy all the common response fields such as status code, headers, and body content, over to your response.
This code isn't tested so you might have to tweak it a bit but it should be enough to get you started.

The format of value 'XXX.yyyyy' is invalid

I am trying to set up if-match header as following and making use of HttpClient available in System.Net.Http:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var adobeRequest = new HttpRequestMessage(HttpMethod.Put, new Uri(url))
{
Content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json")
};
if (!string.IsNullOrEmpty(Etag))
adobeRequest.Headers.Add("If-Match", Etag);
var response = client.SendAsync(adobeRequest);
Etag I received from adobe in previous(Get) call is :
64E8BBA87ACFD0C2C84AF6E1193A3761.5334C3A18AB5A054FF3DBC33AFBDF6C
So when I try to add the same for Put request, it gives me following error:
The format of value
'64E8BBA87ACFD0C2C84AF6E1193A3761.5334C3A18AB5A054FF3DBC33AFBDF6C' is
invalid.
How to resolve this issue? It clearly says format is not valid, however I believe Adobe's api is being used by million others. So somehow Its something from my end.
Link for Adobe api
Use adobeRequest.Headers.TryAddWithoutValidation instead.

Send HTTP Post request in Xamarin Forms C#

Before I start, I would like to say that I have googled solutions to this problem but have either not understood them (I am a newbie) or they do not work.
What I want to do is send JSON data to a REST API on localhost:8000, in this format:
{
"username" : "myusername",
"password" : "mypass"
}
Then, I expect a response which holds a string token, like the following,
{
"token" : "rgh2ghgdsfds"
}
How do send the json data and then parse the token from the response?
I have seen synchronous methods of doing this but for some reason, they do not work (or simply because I do not know what namespace it is in). If you apply an async way of doing this, could you please explain to me how it works?
Thanks in advance.
I use HttpClient. A simple example:
var client = new HttpClient();
client.BaseAddress = new Uri("localhost:8080");
string jsonData = #"{""username"" : ""myusername"", ""password"" : ""mypassword""}"
var content = new StringContent (jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("/foo/login", content);
// this result string should be something like: "{"token":"rgh2ghgdsfds"}"
var result = await response.Content.ReadAsStringAsync();
Where "/foo/login" will need to point to your HTTP resource. For example, if you have an AccountController with a Login method, then instead of "/foo/login" you would use something like "/Account/Login".
In general though, to handle the serializing and deserializing, I recommend using a tool like Json.Net.
As for the question about how it works, there is a lot going on here. If you have questions about how the async/await stuff works then I suggest you read Asynchronous Programming with Async and Await on MSDN
This should be fairly easy with HttpClient.
Something like this could work. However, you might need to proxy data from the device/simulator somehow to reach your server.
var client = new HttpClient();
var content = new StringContent(
JsonConvert.SerializeObject(new { username = "myusername", password = "mypass" }));
var result = await client.PostAsync("localhost:8080", content).ConfigureAwait(false);
if (result.IsSuccessStatusCode)
{
var tokenJson = await result.Content.ReadAsStringAsync();
}
This code would probably go into a method with the following signature:
private async Task<string> Login(string username, string password)
{
// code
}
Watch out using void instead of Task as return type. If you do that and any exception is thrown inside of the method that exception will not bubble out and it will go unhandled; that will cause the app to blow up. Best practice is only to use void when we are inside an event or similar. In those cases make sure to handle all possible exceptions properly.
Also the example above uses HttpClient from System.Net.HttpClient. Some PCL profiles does not include that. In those cases you need to add Microsoft's HttpClient library from Nuget. I also use JSON.Net (Newtonsoft.Json) to serialize the object with username and password.
I would also note that sending username and password in cleartext like this is not really recommended and should be done otherwise.
EDIT: If you are using .NET Standard on most of the versions you won't need to install System.Net.HttpClient from NuGet anymore, since it already comes with it.
try this code.
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(APIAddress); // Insert your API URL Address here.
string serializedObject = JsonConvert.SerializeObject(data);
HttpContent contentPost = new StringContent(serializedObject, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = await httpClient.PostAsync(ControllerWithMethod, contentPost);
return response;
}
catch (TaskCanceledException ex)
{
throw;
}
catch (Exception ex)
{
return new HttpResponseMessage();
}

Categories