I have this REST request; I'm trying to convert it to HttpClient
. I don't want to use RestSharp
in my application.
I'm not sure how to send over an empty body in the request: I keep getting "bad request" when I send a response.
Basically, I call a post
method to log in a user below. It works in RestSharp, but the request needs an empty body to be successful.
var client = new RestClient(Token.Location + "/users/api/login");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", Token.Value);
request.AddHeader("Content-Type", "application/json");
request.AddJsonBody(JsonSerializer.Serialize(new { }));
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
I'm trying to convert this piece of code to use HttpClient
in .net core 3.1.
Here is what I have tried:
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", Token.Value);
var stringContent = new StringContent(string.Empty);
var res = await client.PostAsync(Token.Location + "/users/api/login", stringContent);
var data = await res.Content.ReadAsStringAsync();
I've also tried
...
var content = new StringContent(JsonSerializer.Serialize(new { }), Encoding.UTF8, "application/json");
var res = await client.PostAsync(Token.Location + "/users/api/login", content);
...
var res = await client.PostAsync(Token.Location + "/users/api/login", null);
...
var res = await client.PostAsync(Token.Location + "/users/api/login", "Empty string");
I keep getting "bad request" because I'm not sending over an empty body.
I've tried in postman and it works with an empty raw body of {}
. What am I missing here?
The first thing you want to do is make sure you are using a shared HttpClient. If you are in ASP.NET Core, use IHttpClientFactory
. You can learn why here.
Since you are going to share your HttpClient
, it's good to not use DefaultReqestHeaders
as it will affect all requests, and the header dictionary isn't thread-safe. So if one thread is modifying the collection at the same time another one is, you will crash.
That's not saying that you should never use DefaultRequestHeaders
. They are handy if you don't want to set the same header over and over. You set the value once and all requests share that value.
With that in mind, it is always good to use SendAsync
. This method takes a HttpRequestMessasage
which allows you to isolate the headers to that one request.
A typical usage scenario is:
using (var req = new HttpRequestMessage(HttpMethod.Get,
new Uri("https://www.example.com")))
{
req.Headers.Authorization = new AuthenticationHeaderValue("token");
using (var resp = await _client.SendAsync(req))
{
resp.EnsureSuccessStatusCode();
var data = resp.Content.ReadAsStringAsync();
}
}
This will send a GET request to https://www.example.com
with an Authorization
header with the value token
.
The HttpRequestMessage
has its own set of headers which is used in conjunction with the DefaultRequestHeaders
.
The next thing to consider, and this is out of the scope of your question, but it's worth bringing up: Try to use UriBuilder
when creating your URLs with pieces.
For example:
var uri = new UriBuilder(Token.Location) { Path = "/users/api/login" }.Uri;
Now you don't have to worry if Token.Location
ends with /
or not. The framework will make sure it's well-formed.
As far as posting an object as JSON, here is an example using Newtonsoft.Json
package:
using (var req = new HttpRequestMessage(HttpMethod.Post,
new Uri("https://www.example.com")))
{
req.Headers.Authorization = new AuthenticationHeaderValue("token");
req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
req.Content = new StringContent(
JsonConvert.SerializeObject(theObjectToSend),
Encoding.UTF8,
"application/json");
using (var resp = await _client.SendAsync(req))
{
resp.EnsureSuccessStatusCode();
var data = JsonConvert.DeserializeObject<object>(
await resp.Content.ReadAsStringAsync());
}
}
This will serialize and apply the appropriate headers to your request. It will then read the request back and deserialize it to object
. You'd want to replace object
with a model you create so it's easy to read.
I know this answer is overblown for what you are asking, but I like to give some tips when people first start out with HttpClient
, because there are a few "gotcha's" that get missed.
So, for your answer, take the code above and replace theObjectToSend
with new {}
and see what happens.
If it still isn't working, using something like Fiddler to debug your HTTP calls to see what you are missing.