Get response body from Flurl HttpResponseMessage - c#

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)

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();
}

I am not able to get the response content from API call

I am doing a post request and reading the response as given
var response = client.PostAsync(uriBuilder.Uri.ToString(), Content).Result;
var value = response.Content.ReadAsStreamAsync().Result;
if the result is a proper json string, it populates that in 'value' variable
otherwise it returns empty.
but if run the same in postman or fiddler i get this as response
Is there a way to get this response too?
ReadAsStreamAsync() returns a Task<System.IO.Stream> and not a Task<string>. The json string that you see is probably the debugger showing you the content of the stream.
Consider using ReadAsStringAsync() to get the HTML content :
var response = await client.PostAsync(uriBuilder.Uri.ToString(), Content);
var result = 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);

Getting response header

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>();

How to get HttpContent from Request object?

If a caller adds HttpContent:
using (var content = new MultipartFormDataContent())
{
HttpContent additionalContent = StringContent("just a test");
content.Add(additionalContent);
Which is then POST'ed, how does the receiver retrieve this additional content?
I've seen examples where people call Request.Content. However, HttpContent.Current.Request doesn't have a Content object.
The receiver is an [HttpPost] WebAPI.
Use ReadAsMultipartAsync extension method for getting content parts and then ReadAsStringAsync for parsing string content:
var provider = await Request.Content.ReadAsMultipartAsync();
var content = provider.Contents.FirstOrDefault(); //assumed single content part has been sent
if (content != null)
{
var result = await content.ReadAsStringAsync();
}
I think the body of your request is nothing but content of request.
Please cross check using F12 developers tools->Network-> Request's response section or body section.

Categories