ASP.NET Core convert http response message to IEnumerable - asp.net

I am trying to convert a http response message into an IEnumerable, but I get the error:
JsonException: The JSON value could not be converted to System.Collections.Generic.IEnumerable 1[MyProject.Models.MyClass]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
Here is my code:
[HttpGet]
public async Task<IEnumerable<MyClass>> GetAsync()
{
var httpRequestMessage = new HttpRequestMessage(
HttpMethod.Get,
"https://xxx/api/123")
{
Headers =
{
{ HeaderNames.Authorization, "password" },
}
};
var httpClient = _httpClientFactory.CreateClient();
var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
if (httpResponseMessage.IsSuccessStatusCode)
{
using var contentStream =
await httpResponseMessage.Content.ReadAsStreamAsync();
Ipads = await JsonSerializer.DeserializeAsync
<IEnumerable<MyClass>>(contentStream); // HERE IS WHERE THE ERROR HITS
}
return MyClasses;
}
Here is the same GET but in Postman working:
Thanks beforehand!
Best regards Max

You need to await the content from the HttpResponseMessage as string.
var responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<MyClass>(responseContent);

Related

StatusCode error 500 when sending a POST resquest in XF

I'm writing an API in EF to send FCM notifications:
[HttpPost]
public void PushNotificationToFCM(string deviceTokens, string title, string body, object data, string linkdirection)
{
...
// This registration token comes from the client FCM SDKs.
var registrationToken = deviceTokens;
// See documentation on defining a message payload.
var message = new Message()
{
Apns = new ApnsConfig { Aps = new Aps { ContentAvailable = true, Sound = "default" } },
Data = new Dictionary<string, string>()
{
{ "link", linkdirection },
},
Token = registrationToken,
Notification= new FirebaseAdmin.Messaging.Notification()
{
Title = title,
Body = body,
}
};
// Send a message to the device corresponding to the provided
// registration token.
string response = FirebaseMessaging.DefaultInstance.SendAsync(message).Result;
// Response is a message ID string.
Debug.WriteLine("Successfully sent message: " + response);
}
I tried on Postman or Swagger everything works fine.
I proceed to write the send command in XF:
.xaml.cs
protected async void SendFirebase()
{
string devicetoken = listDeviceID.deviceidphone;
string titlefirebase = "Title";
string bodyfirebase = "Description";
string linkfirebase = "https://applink/..";
await _apiService.AddNotifyFirebase(devicetoken, titlefirebase, bodyfirebase, linkfirebase);
}
public async Task AddNotifyFirebase(string devicetoken, string titlefirebase, string bodyfirebase, string linkfirebase)
{
var model = new
{
devicetoken = devicetoken,
titlefirebase = titlefirebase,
bodyfirebase = bodyfirebase,
linkfirebase = linkfirebase,
};
var json = JsonConvert.SerializeObject(model);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var request = new HttpRequestMessage(HttpMethod.Post, "https://linkapi/api/SendNotifyDeviceFirebase");
request.Content = content;
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseBody = await response.Content.ReadAsStringAsync();
}
}
However I get the error: StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.NSUrlSessionHandler+NSUrlSessionDataTaskStreamContent, ....
Where did I go wrong? Looking forward to everyone's help. Thank you!
Update
I check on Swagger:
Everything seems fine!
I then changed the send command back:
public async Task AddNotifyFirebase(string devicetoken, string titlefirebase, string bodyfirebase, string linkfirebase)
{
var request = new HttpRequestMessage(HttpMethod.Post, "https://xxxxxx/api/SendNotifyDeviceFirebase?deviceTokens=" + devicetoken + "&title=" + titlefirebase + "&body=" + bodyfirebase + "&linkdirection=" + linkfirebase);
//request.Headers.Add("Accept-Encoding", "gzip");
//request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain; charset=utf-8");
HttpResponseMessage response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseBody = await response.Content.ReadAsStringAsync();
}
}
I get the error again: StatusCode: 415, ReasonPhrase: 'Unsupported Media Type'
I have handled the problem. Thank you all
public async Task AddNotifyFirebase(NotifyFireBase NotifyFireBaseAdd)
{
var urlput = "......";
HttpClient client = new HttpClient();
var content = NotifyFireBaseAdd;
var stringContent = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");
await client.PostAsync(urlput, stringContent);
}

HttpClient return json response on localhost when application live on server it's return html

I'm calling API using HttpClient below code running fine on localhost but when it's live on server it's return html response.
here is the code i'm using
public async Task<ActionResult> getPost()
{
string url = "https://www.instagram.com/p/Bg9DwFYHARK/?__a=1";
HttpClient _client = new HttpClient();
var Response = await _client.GetAsync(url);
if (Response.IsSuccessStatusCode)
{
var Result = Response.Content.ReadAsStringAsync().Result;
//here in **Result** i've received html instead of json or when i received html instead
of json got error on DeserializeObject.
var Jsonresult = JsonConvert.DeserializeObject<post>(Result);
return Json(new { isValid = false, error = "post found", obj = Jsonresult }, JsonRequestBehavior.AllowGet);
}
else
{
return Json(new { isValid = false, error = "post not found" }, JsonRequestBehavior.AllowGet);
}
}
This method response is JSON.
string uri = "https://www.instagram.com/p/Bg9DwFYHARK/?__a=1";
private static async Task<ActionResult> getPost(string uri)
{
var webRequest = WebRequest.Create(uri) as HttpWebRequest;
if (webRequest == null)
{
return;
}
webRequest.ContentType = "application/json";
webRequest.UserAgent = "Nothing";
using (var s = webRequest.GetResponse().GetResponseStream())
{
using (var sr = new StreamReader(s))
{
// var contributorsAsJson = sr.ReadToEnd();
var contributors = JsonConvert.DeserializeObject<Create a list >(contributorsAsJson);
// contributors.ForEach(Console.WriteLine);
return contributors;
}
}
}
I get out put is:
{"graphql":{"shortcode_media":{"__typename":"GraphImage","id":"1746568728937235530","shortcode":"Bg9DwFYHARK","dimensions":{"height":1080,"width":1080},"gating_info":null,"fact_check_overall_rating":null,"fact_check_information":null,"sensitivity_friction_info":null,"media_overlay_info":null,"media_preview":"ACoqytpjBOM+tQs6t07nvxwOn4889q2TDuGKzrfT2kkKtkBDz7j2PT0/OlpuUm7cvQqrbSS/cBb6D/IqI8DHfvXZiVI12qpBA+7xwPr0/WueMXm3LMBx94jryf0PrSTdwaVrlSKMsKd5ZrYji7n8B/8AWp3k+wp3ILSKT0FBkW2YM/AcEZ9xz+o4+uBVgyBSB26VDcWgnYFuVUEbfr3B9Qarl0HcRrgqQWVlX5snjIBxgsOw9fTFR2xEu+QdHbj6DgH8earPayvuUuXXHTGC2OgZv5461pQRGKNY+PlABx69/wBamKvuVJ9iMgikqwy4qPZSasJambblpm3dlP5n69x/9atgetZ1h/qV/H+ZrQHQfhWl7tk2JqY7bQT6UtRvTAN2aZUSnn8am2L6D8qdk9xbH//Z","display_url":"https://instagram.fcok6-1.fna.fbcdn.net/v/t51.2885-15/e35/29400587_173904939930435_4131401846013034496_n.jpg?_nc_ht=instagram.fcok6-1.fna.fbcdn.net&_nc_cat=103&_nc_ohc=cgtRDraKPGoAX_a9AvI&oh=fc8640215bbe4a5003bbaf694113951c&oe=5F2FFE5A","display_resources":[{"src":"https://instagram.fcok6-1.fna.fbcdn.net/v/t51.2885-15/sh0.08/e35/s640x640/29400587_173904939930435_4131401846013034496_n.jpg?_nc_ht=instagram.fcok6-1.fna.fbcdn.net&_nc_cat=103&_nc_ohc=cgtRDraKPGoAX_a9AvI&oh=e971123fdc4eb19abe4a96b35195dd9f&oe=5F30CFBD","config_width":640,"config_height":640},{"src":"https://instagram.fcok6-1.fna.fbcdn.net/v/t51.2885-15/sh0.08/e35/s750x750/29400587_173904939930435_4131401846013034496_n.jpg?_nc_ht=instagram.fcok6-1.fna.fbcdn.net&_nc_cat=103&_nc_ohc=cgtRDraKPGoAX_a9AvI&oh=33fe7c336ecff4205e161452adfc7ecf&oe=5F31703D","config_width":750,"config_height":750},{"src":"https://instagram.fcok6-1.fna.fbcdn.net/v/t51.2885-15/e35/29400587_173904939930435_4131401846013034496_n.jpg?_nc_ht=instagram.fcok6-1.fna.fbcdn.net&_nc_cat=103&_nc_ohc=cgtRDraKPGoAX_a9AvI&oh=fc8640215bbe4a5003bbaf694113951c&oe=5F2FFE5A","config_width":1080,"config_height":1080}],"accessibility_caption":"Photo by Ateeq Khalil in Salt N Pepper Liberty. Image may contain: 1 person","is_video":false,"tracking_token":"eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjp0cnVlLCJ1dWlkIjoiZWQ2ZjUxNTZjMjc5NDU5MzlmMmQ1MTQzZDBhZmIyYjYxNzQ2NTY4NzI4OTM3MjM1NTMwIn0sInNpZ25hdHVyZSI6IiJ9","edge_media_to_tagged_user":{"edges":[]},"edge_media_to_caption":{"edges":[]},"caption_is_edited":false,"has_ranked_comments":false,"edge_media_to_parent_comment":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]},"edge_media_to_hoisted_comment":{"edges":[]},"edge_media_preview_comment":{"count":0,"edges":[]},"comments_disabled":false,"commenting_disabled_for_viewer":false,"taken_at_timestamp":1522427239,"edge_media_preview_like":{"count":19,"edges":[]},"edge_media_to_sponsor_user":{"edges":[]},"location":{"id":"1730525857251432","has_public_page":true,"name":"Salt N Pepper Liberty","slug":"salt-n-pepper-liberty","address_json":"{\"street_address\": \"48 Commercial Zone Liberty Market, Gulberg III\\u060c\", \"zip_code\": \"\", \"city_name\": \"Lahore, Pakistan\", \"region_name\": \"\", \"country_code\": \"PK\", \"exact_city_match\": false, \"exact_region_match\": false, \"exact_country_match\": false}"},"viewer_has_liked":false,"viewer_has_saved":false,"viewer_has_saved_to_collection":false,"viewer_in_photo_of_you":false,"viewer_can_reshare":true,"owner":{"id":"5394358177","is_verified":false,"profile_pic_url":"https://instagram.fcok6-1.fna.fbcdn.net/v/t51.2885-19/s150x150/29402856_149619235868663_6235876322871083008_n.jpg?_nc_ht=instagram.fcok6-1.fna.fbcdn.net&_nc_ohc=gSyry9Wj5UkAX_bQlzD&oh=bdc6a6b82077c8e461aedbaffa7e49db&oe=5F32308B","username":"ateeq.khalil","blocked_by_viewer":false,"restricted_by_viewer":null,"followed_by_viewer":false,"full_name":"Ateeq Khalil","has_blocked_viewer":false,"is_private":false,"is_unpublished":false,"requested_by_viewer":false,"edge_owner_to_timeline_media":{"count":7},"edge_followed_by":{"count":175}},"is_ad":false,"edge_web_media_to_related_media":{"edges":[]},"edge_related_profiles":{"edges":[]}}}}

HttpResponseMessage Send & Receive List or Array of <T>

With the latest System.Net.Http.Json there are some methods that help with serializing / deserializing. I want to use the HttpResponseMessage Content hold my response Objects. They seem to store fine on the server but when I get them on the client side the Content is not what I was expecting. There is a lot of additional data injected and I am lost on how I can pass some data with additional meta data.
I am not sure what is going on.. If I try to use:
Content = new StringContent("test content")
on the client side I get "test content" but I get this:
Content:
{"version":"1.1","content":{"headers":[{"key":"Content-Type","value":["text/plain; charset=utf-8"]}]},"statusCode":200,"reasonPhrase":"Retrieved
Forecasts","headers":[],"trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}
Here is my Blazor code:
Client:
protected override async Task OnInitializedAsync()
{
try
{
//forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
HttpResponseMessage httpResponse = await Http.GetAsync("WeatherForecast");
if (httpResponse.IsSuccessStatusCode)
{
Console.WriteLine("Response Weather");
//forecasts = (await httpResponse.Content.ReadFromJsonAsync<WeatherForecast[]>()).ToList<WeatherForecast>();
Console.WriteLine("Content: " + await httpResponse.Content.ReadAsStringAsync());
//forecasts = Newtonsoft.Json.JsonConvert.DeserializeObject<WeatherForecast[]>(await httpResponse.Content.ReadAsStringAsync()).ToList<WeatherForecast>(); // Doesn't work
forecasts = await httpResponse.Content.ReadFromJsonAsync<WeatherForecast[]>(); //Doesn't work
}
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
Server:
[HttpGet]
public async Task<HttpResponseMessage> Get()
{
var rng = new Random();
WeatherForecast[] weather = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
HttpResponseMessage message = new HttpResponseMessage
{
StatusCode = OK,
ReasonPhrase = "Retrieved Weather",
//Content = new StringContent("test content")
//Content = JsonContent.Create<WeatherForecast[]>(weather)
//Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(weather))
};
string test = await message.Content.ReadAsStringAsync(); // This looks correct!
return message;
}

Read Asp.Net Core Response body in ActionFilterAttribute

I'm using Asp.Net Core as a Rest Api Service.
I need access to request and response in ActionFilter. Actually, I found the request in OnActionExcecuted but I can't read the response result.
I'm trying to return value as follow:
[HttpGet]
[ProducesResponseType(typeof(ResponseType), (int)HttpStatusCode.OK)]
[Route("[action]")]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
var model = await _responseServices.Get(cancellationToken);
return Ok(model);
}
And in ActionFilter OnExcecuted method as follow:
_request = context.HttpContext.Request.ReadAsString().Result;
_response = context.HttpContext.Response.ReadAsString().Result; //?
I'm trying to get the response in ReadAsString as an Extension method as follow:
public static async Task<string> ReadAsString(this HttpResponse response)
{
var initialBody = response.Body;
var buffer = new byte[Convert.ToInt32(response.ContentLength)];
await response.Body.ReadAsync(buffer, 0, buffer.Length);
var body = Encoding.UTF8.GetString(buffer);
response.Body = initialBody;
return body;
}
But, there is no result!
How I can get the response in OnActionExcecuted?
Thanks, everyone for taking the time to try and help explain
If you're logging for json result/ view result , you don't need to read the whole response stream. Simply serialize the context.Result:
public class MyFilterAttribute : ActionFilterAttribute
{
private ILogger<MyFilterAttribute> logger;
public MyFilterAttribute(ILogger<MyFilterAttribute> logger){
this.logger = logger;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
var result = context.Result;
if (result is JsonResult json)
{
var x = json.Value;
var status = json.StatusCode;
this.logger.LogInformation(JsonConvert.SerializeObject(x));
}
if(result is ViewResult view){
// I think it's better to log ViewData instead of the finally rendered template string
var status = view.StatusCode;
var x = view.ViewData;
var name = view.ViewName;
this.logger.LogInformation(JsonConvert.SerializeObject(x));
}
else{
this.logger.LogInformation("...");
}
}
I know there is already an answer but I want to also add that the problem is the MVC pipeline has not populated the Response.Body when running an ActionFilter so you cannot access it. The Response.Body is populated by the MVC middleware.
If you want to read Response.Body then you need to create your own custom middleware to intercept the call when the Response object has been populated. There are numerous websites that can show you how to do this. One example is here.
As discussed in the other answer, if you want to do it in an ActionFilter you can use the context.Result to access the information.
For logging whole request and response in the ASP.NET Core filter pipeline you can use Result filter attribute
public class LogRequestResponseAttribute : TypeFilterAttribute
{
public LogRequestResponseAttribute() : base(typeof(LogRequestResponseImplementation)) { }
private class LogRequestResponseImplementation : IAsyncResultFilter
{
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
var requestHeadersText = CommonLoggingTools.SerializeHeaders(context.HttpContext.Request.Headers);
Log.Information("requestHeaders: " + requestHeadersText);
var requestBodyText = await CommonLoggingTools.FormatRequestBody(context.HttpContext.Request);
Log.Information("requestBody: " + requestBodyText);
await next();
var responseHeadersText = CommonLoggingTools.SerializeHeaders(context.HttpContext.Response.Headers);
Log.Information("responseHeaders: " + responseHeadersText);
var responseBodyText = await CommonLoggingTools.FormatResponseBody(context.HttpContext.Response);
Log.Information("responseBody: " + responseBodyText);
}
}
}
In Startup.cs add
app.UseMiddleware<ResponseRewindMiddleware>();
services.AddScoped<LogRequestResponseAttribute>();
Somewhere add static class
public static class CommonLoggingTools
{
public static async Task<string> FormatRequestBody(HttpRequest request)
{
//This line allows us to set the reader for the request back at the beginning of its stream.
request.EnableRewind();
//We now need to read the request stream. First, we create a new byte[] with the same length as the request stream...
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
//...Then we copy the entire request stream into the new buffer.
await request.Body.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
//We convert the byte[] into a string using UTF8 encoding...
var bodyAsText = Encoding.UTF8.GetString(buffer);
//..and finally, assign the read body back to the request body, which is allowed because of EnableRewind()
request.Body.Position = 0;
return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
}
public static async Task<string> FormatResponseBody(HttpResponse response)
{
//We need to read the response stream from the beginning...
response.Body.Seek(0, SeekOrigin.Begin);
//...and copy it into a string
string text = await new StreamReader(response.Body).ReadToEndAsync();
//We need to reset the reader for the response so that the client can read it.
response.Body.Seek(0, SeekOrigin.Begin);
response.Body.Position = 0;
//Return the string for the response, including the status code (e.g. 200, 404, 401, etc.)
return $"{response.StatusCode}: {text}";
}
public static string SerializeHeaders(IHeaderDictionary headers)
{
var dict = new Dictionary<string, string>();
foreach (var item in headers.ToList())
{
//if (item.Value != null)
//{
var header = string.Empty;
foreach (var value in item.Value)
{
header += value + " ";
}
// Trim the trailing space and add item to the dictionary
header = header.TrimEnd(" ".ToCharArray());
dict.Add(item.Key, header);
//}
}
return JsonConvert.SerializeObject(dict, Formatting.Indented);
}
}
public class ResponseRewindMiddleware {
private readonly RequestDelegate next;
public ResponseRewindMiddleware(RequestDelegate next) {
this.next = next;
}
public async Task Invoke(HttpContext context) {
Stream originalBody = context.Response.Body;
try {
using (var memStream = new MemoryStream()) {
context.Response.Body = memStream;
await next(context);
//memStream.Position = 0;
//string responseBody = new StreamReader(memStream).ReadToEnd();
memStream.Position = 0;
await memStream.CopyToAsync(originalBody);
}
} finally {
context.Response.Body = originalBody;
}
}
You can also do...
string response = "Hello";
if (result is ObjectResult objectResult)
{
var status = objectResult.StatusCode;
var value = objectResult.Value;
var stringResult = objectResult.ToString();
responce = (JsonConvert.SerializeObject(value));
}
I used this in a .net core app.
Hope it helps.

How do I call WebApi method with parameters

I have a WebApi method with 2 parameters as followed:
public IQueryable<Facilities> GetFacilityList(string baseCode, string scope)
{
return Object;
}
In my Asp.Net MVC I have the following so far:
public ActionResult FacilityGrid()
{
List<Facilities> query;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:8080/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/facilities");
if (response.IsSuccessStatusCode)
{
// Product product = await response.Content.ReadAsAsync>Product>()
}
}
}
How do I call the WebApi and pass in two parameters?
You could create the query string manually as suggested in the comment to your post of code or by using a class like the UriBuilder. This method seemed produce the desired response.
public async Task<ActionResult> QuetionTwoApiCall()
{
var builder = new UriBuilder("http://localhost/api/question2");
builder.Port = 50742;
var query = HttpUtility.ParseQueryString(builder.Query);
query["basecode"] = "somebasecode";
query["scope"] = "somescope";
builder.Query = query.ToString();
string url = builder.ToString();
using (var client = new HttpClient()) {
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(new Uri(url));
string donothing = "do nothing";
}
return RedirectToAction("QuestionTwo");
}
}

Resources