Getting response header - c#

Used the Flurl to Get response from API.
var response = await url.WithClient(fc)
.WithHeader("Authorization", requestDto.ApiKey)
.GetJsonAsync<T>();
dynamic httpResponse = response.Result;
But I cant able to access httpResponse.Headers
How to access response headers while using GetJsonAsync .

You can't get a header from GetJsonAsync<T> because it returns Task<T> instead of raw response. You can call GetAsync and deserialize your payload at next step:
HttpResponseMessage response = await url.GetAsync();
HttpResponseHeaders headers = response.Headers;
FooPayload payload = await response.ReadFromJsonAsync<FooPayload>();
ReadFromJsonAsync is an extention method:
public static async Task<TBody> ReadFromJsonAsync<TBody>(this HttpResponseMessage response)
{
if (response.Content == null) return default(TBody);
string content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<TBody>(content);
}
P.S. This is why I prefer and recommend to use raw HttpClient instead of any third-party high-level client like RestSharp or Flurl.

You could also await for the HttpResponseMessage, pick off the .Headers object, then send the completed task to ReceiveJson<T> for deserialization. Here's how to do it without an extension method:
var task = url.GetAsync();
HttpResponseMessage response = await task;
HttpResponseHeaders headers = response.Headers;
//Get what I need now from headers, .ReceiveJson<T>() will dispose
//response object above.
T obj = await task.ReceiveJson<T>();

Related

HttpClient Get 401

I'm trying to call a Tableau endpoint to get the list of project.
It is in 2 steps:
Call the signIn endpoint to get a token that allow to call others endpoint
Call the list projects endpoint with my signed In token
By using insomnia, this is working like a charm, but in csharp code, the first step is working well, but the second always returning me a 401 error.
Tableau list projects documentation
public async Task<string> ListProjectAsync()
{
var signIn = await SignInAsync(); // Working
var endPoint = $"https://myTableauSite.com/api/3.17/sites/{signIn.SiteId}/projects";
var acceptedCodes = new List<HttpStatusCode>();
acceptedCodes.Add(HttpStatusCode.OK);
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Tableau-Auth", signIn.Token);
HttpResponseMessage response = await client.GetAsync(endPoint); // 401
response.EnsureSuccessStatusCode();
string responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
Edit: The problem was from the JWT generated token that had a missing permission, my bad
The only difference I could find between your code's request and insomnia is that you forgot to set the content-type
public async Task<string> ListProjectAsync()
{
var signIn = await SignInAsync(); // Working
var endPoint = $"https://myTableauSite.com/api/3.17/sites/{signIn.SiteId}/projects";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Content-Type", "application/xml");
client.DefaultRequestHeaders.Add("X-Tableau-Auth", signIn.Token);
HttpResponseMessage response = await client.GetAsync(endPoint); // Should be working
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}

HttpResponseMessage content is being returned as unicode

I am trying to read the contents of a HttpResponseMessage message as a string. However, it appears to be being returned as unicode.
This is my code that I am using to make the request with HttpClient
var responseMsg = await httpClient
.SendAsync(requestMsg, HttpCompletionOption.ResponseContentRead)
.ConfigureAwait(false);
return await BuildResponse(responseMsg, cookieContainer.GetAllCookies().ToList()).ConfigureAwait(false);
And here is my code for BuildResponse
private static async Task<IResponse> BuildResponse(HttpResponseMessage responseMsg, List<Cookie> cookies)
{
Ensure.ArgumentNotNull(responseMsg, nameof(responseMsg));
// We only support text stuff for now
using var content = responseMsg.Content;
var headers = responseMsg.Headers.ToDictionary(header => header.Key, header => header.Value.First());
var body = await responseMsg.Content.ReadAsStringAsync().ConfigureAwait(false);
var contentType = content.Headers?.ContentType?.MediaType;
return new Response(headers)
{
ContentType = contentType,
StatusCode = responseMsg.StatusCode,
Body = body,
CookieCollection = cookies
};
}
I know that the API call is working correctly, as I can see the exact request in fiddler return the JSON I am expecting:
What am I doing wrong? I should get the JSON returned as shown in screenshot 2.
try to check your response data:
var body = await responseMsg.Content.ReadAsStringAsync();
var data= JsonConvert.DeserializeObject<your response data class>(body);

Get response body from Flurl HttpResponseMessage

Im making some automatic surveillance for an Rest API im running and i need to retrieve the response body from the HttpResponseMessage object.
Im using Flurl Http: https://flurl.dev/docs/fluent-http/
I know how to retrieve the responsebody by adding ".RecieveSomeForm()" at the end of the http request, but i also need to get the response headers, as the error code from the Rest API is sent back as a header. My problem is that - to my knowledge and what i tried - its only the HttpResponseMessage object that i can retrieve the headers from. So the question is:
How do i get the responsebody out of the HttpResponseMessage while still being able to retrieve the headers for error logging?
using (var cli = new FlurlClient(URL).EnableCookies())
{
//get response body - var is set to string and has only response body
var AsyncResponse = await cli.WithHeader("some header").Request("some end point").AllowAnyHttpStatus().PostJsonAsync(some body).ReceiveString();
Console.WriteLine(AsyncResponse);
//get headers - var is set to HttpResponseMessage
var AsyncResponse = await cli.WithHeader("some header").Request("some end point").AllowAnyHttpStatus().PostJsonAsync(some body);
Console.WriteLine(AsyncResponse.Headers);
}
If I've understood correctly, you want Headers + Response body from a HTTP response.
var response = await cli.WithHeader("some header").Request("some end point").AllowAnyHttpStatus().PostJsonAsync("some body");
var headers = response.Headers; //do your stuff
var responseBody = response.Content != null ? await response.Content.ReadAsStringAsync() : null;
Another option which I personally don't like:
var responseTask = cli.WithHeader("some header", "haha").Request("some end point").AllowAnyHttpStatus().PostJsonAsync("some body");
var headers = (await responseTask).Headers; //do your stuff
var responseBody = await responseTask.ReceiveString();
Unfortunately, Flurl's extension methods can be used on Task, not on HttpResponseMessage. (that's why you have to avoid awaiting in the first line of code)

C# .NET web api return from post request

I am making a POST request to a route which is returning JSON data.
[HttpPost("api/v1/testGetAll")]
public object Test([FromBody]object filteringOptions)
{
return myService.GetLogs(filteringOptions).ToArray();
}
Route works fine, filtering works fine, and when I test the route in Postman I get the right response. However this is only a back-end, and I would like to invoke this route from my custom API gateway.
The issue I'm facing is getting that exact response back. Instead I am getting success status, headers, version, request message etc.
public object TestGetAll(string ApiRoute, T json)
{
Task<HttpResponseMessage> response;
var url = ApiHome + ApiRoute;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
try
{
response = client.PostAsync(url, new StringContent(json.ToString(), Encoding.UTF8, "application/json"));
return response.Result;
}
catch (Exception e)
{
...
}
}
}
How can I get exact content back?
You need to read the content from response.
var contentString = response.Result.Content.ReadAsStringAsync().Result;
If you wish, you can then deserialize the string response into the object you want returning.
public async Task<TResult> TestGetAll<TResult>(string apiRoute, string json)
{
// For simplicity I've left out the using, but assume it in your code.
var response = await client.PostAsJsonAsync(url, json);
var resultString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<TResult>(resultString);
return result;
}
You have to return the response as an HttpResponseMessage.
Try changing your return statement to
[HttpPost("api/v1/testGetAll")]
public IHttpActionResult Test([FromBody]object filteringOptions)
{
return Ok(myService.GetLogs(filteringOptions).ToArray());
}
Please note: This will return the response with status code 200. In case you want to handle the response based on different response code. You can create the HttpResponseMessage like this-
Request.CreateResponse<T>(HttpStatusCode.OK, someObject); //success, code- 200
Request.CreateResponse<T>(HttpStatusCode.NotFound, someObject); //error, code- 404
T is your object type.
And so on...

.NET HttpClient Request Content-Type

I'm not sure, but it appears to me that the default implementation of .NET HttpClient library is flawed. It looks like it sets the Content-Type request value to "text/html" on a PostAsJsonAsync call. I've tried to reset the request value, but not sure if I'm doing this correctly. Any suggestions.
public async Task<string> SendPost(Model model)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync(Url + "api/foo/", model);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
You should set the content type. With the Accept you define what you want as response.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
The Accept request-header field can be used to specify certain media types which are acceptable for the response. Accept headers can be used to indicate that the request is specifically limited to a small set of desired types, as in the case of a request for an in-line image.
public async Task<string> SendPost(Model model)
{
var client = new HttpClient(); //You should extract this and reuse the same instance multiple times.
var request = new HttpRequestMessage(HttpMethod.Post, Url + "api/foo");
using(var content = new StringContent(Serialize(model), Encoding.UTF8, "application/json"))
{
request.Content = content;
var response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}

Categories