Reading and DeserializeObject Response Header using Asp Core 3.1 - asp.net-core

I'm try to make a paging for collection, I have a Web API and I'm sending paging data into header like total count and next page link so I can read the response header and put it into string as a Json here is my consume code
public async Task<MultibleValuesHelper> GetAllTags()
{
IEnumerable<TagModelDto> tags;
IEnumerable<PagedDataModel> Header=null;
using (var response = await _httpClient.GetAsync($"tag"))
{
string apiResponse = await response.Content.ReadAsStringAsync();
if( response.Headers.TryGetValues("X-Pagenation", out var Pagenation))
{
var TryHeader = Pagenation.FirstOrDefault();
Header = JsonConvert.DeserializeObject<List<PagedDataModel>>(TryHeader);
}
tags = JsonConvert.DeserializeObject<List<TagModelDto>>(apiResponse);
}
return new MultibleValuesHelper {
TagServiceCollection = tags,
HeaderPagenation = Header
};
}
my problem when I'm try to Deserialize header it showen Error :JsonSerializationException: Cannot deserialize the current JSON object So how I can Deserialize Header and put it into IEnumerable Header so I can handle it

Okay the answer is a little bit change in the code we will use PagedDataModel instead List, and here is the full code
public async Task<MultibleValuesHelper> GetAllTags()
{
IEnumerable<TagModelDto> tags;
PagedDataModel Header=new PagedDataModel ;
using (var response = await _httpClient.GetAsync($"tag"))
{
string apiResponse = await response.Content.ReadAsStringAsync();
if( response.Headers.TryGetValues("X-Pagenation", out var Pagenation))
{
var TryHeader = Pagenation.FirstOrDefault();
Header = JsonConvert.DeserializeObject<PagedDataModel>(TryHeader);
}
tags = JsonConvert.DeserializeObject<List<TagModelDto>>(apiResponse);
}
return new MultibleValuesHelper {
TagServiceCollection = tags,
HeaderPagenation = Header
};
}
this is will work Thanks for all of you

Related

Error in ASP.NET Core MVC and Web API project

I have an ASP.NET Core MVC and also Web API project.
This error occurs when I try to send project information to the API (of course API works fine and I do not think there is a problem):
UnsupportedMediaTypeException: No MediaTypeFormatter is available to read a "TokenModel" object of "text / plain" media content.
My code is:
public class TokenModel
{
public string Token { get; set; }
}
and in AuthController I have:
var _Client = _httpClientFactory.CreateClient("MyApiClient");
var jsonBody = JsonConvert.SerializeObject(login);
var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
var response = _Client.PostAsync("/Api/Authentication", content).Result;
if (response.IsSuccessStatusCode)
{
var token = response.Content.ReadAsAsync<TokenModel>().Result;
}
The error occurs on this line:
var token = response.Content.ReadAsAsync<TokenModel>().Result;
HomeController:
public IActionResult Index()
{
var token = User.FindFirst("AccessToken").Value;
return View(_user.GetAllUsers(token));
}
UserRepository:
public List<UserViewModel> GetAllUsers(string token)
{
_client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var res = _client.GetStringAsync(UrlMyApi).Result;
List<UserViewModel> users = JsonConvert.DeserializeObject<List<UserViewModel>>(res);
return users;
}
Your API is returning content-type of text/plain and none of the default media type formatters(MediaTypeFormatter) which ReadAsAsync<string>() will try to use support parsing it as is. They work with JSON/XML. You can go a couple of ways but maybe the easiest is to read the content as string and deserialize it after:
var tokenJSON = response.Content.ReadAsStringAsync().Result;
var token = JsonConvert.DeserializeObject<TokenModel>(tokenJSON);
Also, as you're using the Async methods, you should be returning Task from your actions and await the result instead of using .Result as you're just creating overhead currently.
var tokenJSON = await response.Content.ReadAsStringAsync();
var token = JsonConvert.DeserializeObject<TokenModel>(tokenJSON);

Is there any in-built function/method to return, IActionResult/ActionResult instead of HttpResponseMessage in .Net Core 3.1

My Action method is returning HttpResponseMessage but, I want to get rid off Microsoft.AspNetCore.Mvc.WebApiCompatShim NuGet Package (which is basically provided to bridge the gap while porting Asp.Net Web API code into .Net Core) and use IActionResult/ActionResult instead of HttpResponseMessage.
My Action method looks like this:
[HttpGet]
[Route("GetTemplate")]
public async Task<HttpResponseMessage> GetTemplate(string id) {
var userAgent = this.Request.Headers.UserAgent;
bool IsWindows = true;
if(userAgent.ToString().ToLower().Contains("apple")) {
IsWindows = false; //false
}
var template = await _templateService.GetTemplateContent(id);
HttpResponseMessage responseMsg = new HttpResponseMessage();
if(IsWindows) {
responseMsg.Content = new StringContent(JsonConvert.SerializeObject(template));
responseMsg.RequestMessage = Request;
responseMsg.StatusCode = HttpStatusCode.OK;
responseMsg.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/json");
} else {
responseMsg.Content = new ByteArrayContent(template.ContentBytes);
responseMsg.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileNameStar = template.Name };
responseMsg.Content.Headers.Add("x-filename", template.Name);
responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
responseMsg.Content.Headers.ContentLength = template.ContentBytes.Length;
responseMsg.RequestMessage = Request;
responseMsg.StatusCode = HttpStatusCode.OK;
}
return (responseMsg);
}
Since you aren’t doing anything fancy there, you can translate your return object directly into corresponding action results here. In your case, you want a JsonResult and a FileResult with a custom response header:
[HttpGet]
[Route("GetTemplate")]
public async Task<HttpResponseMessage> GetTemplate(string id)
{
var userAgent = this.Request.Headers.UserAgent;
bool IsWindows = !userAgent.ToString().ToLower().Contains("apple");
var template = await _templateService.GetTemplateContent(id);
if (IsWindows)
{
return Json(template);
}
else
{
Response.Headers.Add("x-filename", template.Name);
return File(template.ContentBytes, "application/octet-stream", template.Name);
}
}
There are a lot similar utility methods on the Controller and ControllerBase type that help you create a variety of different response messages. For most use cases, there should be a built-in way to produce the response.
1stly change the signature of your action to this:
public async Task<IActionResult> GetTemplate
You will then return your data in the response something like this return Ok(data). You do not have to serialize your data, you can send a POCO class. This would represent .StatusCode = HttpStatusCode.OK
If you want to add extra headers to your response, you will do so using the Response field from ControllerBase. Eg. Response.Headers.Add for adding key value pairs to your Response header.

ASP.NET Core 3.1 - PostAsync/PostAsJsonAsync method in Integration Test always returns Bad Request

This is my register method inside the AuthController.
[HttpPost(ApiRoutes.Auth.Register)]
public async Task<IActionResult> Register(UserRegistrationRequest request)
{
var authResponse = await _authService.RegisterAsync(request.Email, request.Password);
if (!authResponse.Success)
{
return BadRequest(new AuthFailedResponse
{
Errors = authResponse.Errors
});
}
return Ok(new AuthSuccessResponse
{
Token = authResponse.Token,
RefreshToken = authResponse.RefreshToken
});
}
I'm trying to call this method by using TestClient.PostAsync() method, unfortunately it always returns Bad Request. I've already tried calling the TestClient.PostAsJsonAsync(ApiRoutes.Auth.Register, user) method by importing Microsoft.AspNet.WebApi.Client package, the result is the same.
var user = new UserRegistrationRequest
{
Email = "user1#testtest.com",
Password = "P#ssw0rd1!!!!!"
};
var response = await TestClient.PostAsync(
ApiRoutes.Auth.Register,
new StringContent(JsonConvert.SerializeObject(user), Encoding.UTF8)
{
Headers = { ContentType = new MediaTypeHeaderValue("application/json") }
});
You are missing the FromBody attribute from you action parameter. When you are sending json data to a controller that will be part of the request body. You can tell to the controller how to bind the incoming data, in your case from the body. So you code should look like:
public async Task<IActionResult> Register([FromBody]UserRegistrationRequest request)
{
…
}
You could read more about bindings in the official documentation.

Asp.Net Core - Making API calls from backend

I have an application which is calling API's from a backend cs class, using IHostedService. With basic API calls ("http://httpbin.org/ip") it is working fine and returning the correct value, however I now need to call a Siemens API which requires me to set an Authorization header, and place "grant_type=client_credentials" in the body.
public async Task<string> GetResult()
{
string data = "";
string baseUrl = "https://<space-name>.mindsphere.io/oauth/token";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", {ServiceCredentialID: ServiceCredentialSecret});
using (HttpResponseMessage res = await client.GetAsync(baseUrl))
{
using (HttpContent content = res.Content)
{
data = await content.ReadAsStringAsync();
}
}
}
I think I have the header set up correctly but I won't know for sure until the full request gets formatted. Is it even possible to set the the body of the request to "grant_type=client_credentials"?
As far as I can see from Siemens API documentation they expect Form data, so it should be like:
public async Task<string> GetResult()
{
string data = "";
string baseUrl = "https://<space-name>.mindsphere.io/oauth/token";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", {ServiceCredentialID: ServiceCredentialSecret});
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "client_credentials")
});
using (HttpResponseMessage res = await client.PostAsync(baseUrl, formContent))
{
using (HttpContent content = res.Content)
{
data = await content.ReadAsStringAsync();
}
}
}
}

PostAsync request with Array parameter on MVC Web API

I have Xamarin application that has POST request with array list of parameter and on my MVC WEB API we used code first Entity framework. Both was separated project solutions (.sln).
On my Xamarin project, I have PostAsync request which supplies List of array values.
using (var client = new HttpClient())
{
Parameter = string.Format("type={0}&param={1}",type, param[]);
var data = JsonConvert.SerializeObject(parameters);
var content = new StringContent(data, Encoding.UTF8, "application/json");
using (var response = await client.PostAsync(url, content))
{
using (var responseContent = response.Content)
{
result = await responseContent.ReadAsStringAsync();
}
}
}
Then In my Web API controller I have same parameter with my client side also.
[System.Web.Http.AcceptVerbs("GET", "POST")]
[System.Web.Http.HttpPost]
[Route("type={type}&param={param}")]
public BasicResponse applog([FromUri] ProfilingType type , List<string> param)
{
if (ModelState.IsValid == false)
{
throw new ModelValidationException("Model state is invalid.");
}
try
{
if(type == ProfilingType.Login)
{
var command = new SendDataProfilingCommand(param);
CommandHandler.Execute(command);
}
else
{
var command = new UpdateDataProfilingCommand(type,param);
CommandHandler.Execute(command);
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
return new BasicResponse
{
Status = true,
Message = Ok().ToString()
};
}
Since I'm not with the API, I want to test it first on Postman or even in the URL. but my problem was when i Try to test it using this url below
http://localhost:59828/api/users/applog?type=1&param=[1,Caloocan,Metro Manila,Philippines,0,0]
I received this message : No HTTP resource was found that matches the request URI ......
My Question is, How can I test my Web API with List Parameter on URL or in the Postman ? and What Format I can use when sending a post request into my Xamarin PostAsync request?
You don't need to send as Content.
using (var client = new HttpClient())
{
Parameter = string.Format("type={0}&param={1}",type, param[]);
url = url + "?" + Parameter;
using (var response = await client.PostAsync(url))
{
using (var responseContent = response.Content)
{
result = await responseContent.ReadAsStringAsync();
}
}
}