Consume API into aspnet core 2.2 - api

I have a web API which returns about 1000 records into json. Now I want to get all those records from json response and deserialize into a model
The code i have written so far is like following:
public async Task<IActionResult> GetList()
{
Facility facilityInfo = new Facility();
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync("http://localhost:55555/api/Facilities"))
{
string apiResponse = await response.Content.ReadAsStringAsync();
facilityInfo = JsonConvert.DeserializeObject<Facility>(apiResponse);
}
}
//-----------other parts of code-----------------
return View();
}
The problem is that it returns null facilityInfo
Thank you

You're deserializing something that has a property called items which is a list of Facilities. So if you have the following structure:
public class Facilities
{
public List<Facility> items;
}
And then
Facilities facilities = JsonConvert.DeserializeObject<Facilities>(apiResponse);
The facilities.items property will contain the data.

Related

HttpClient.GetAsync return HttpResponseMessage with null header

net 5.0 lover.
I am new in blazor and .net 5.0, I develop the application with blazor WebAssembly and WebApi.
There are two major Projects: Client, Server.
Client is Blazor WebAssembly and Server is WebApi Controller Project.
In server side, in controller, HttpGet Method, i add a value to Response header:
[HttpGet]
public async Task<ActionResult<IList<Country>>> GetAsync([FromQuery] Pagination paginationDto)
{
/...
httpContext.Response.Headers.Add("TotalPages", totalPages.ToString());
//...
IList<Country> = ...
return result;
}
In Client project razor page, call the api with following method from generic calss:
protected virtual async Task<PaginatedResponse<O>> GetAsync<O>(Pagination pagination)
{
HttpResponseMessage response = null;
try
{
response = await httpClient.GetAsync(RequestUri);
if (response.IsSuccessStatusCode)
{
try
{
//This response Header always is null!
System.Console.WriteLine("response.Headers: " + response.Headers.ToString());
O result = await response.Content.ReadFromJsonAsync<O>();
var paginatedResponse = new PaginatedResponse<O>
{
Response = result,
TotalPages = totalPages
};
return paginatedResponse;
}
//...
return default;
}
When Api call from postman the result and Header is fine and TotalPages is there.
In Client App, the result is ok, but the Header is null.
Any information will save me ;-)
Thanks in Advance.
I think you're overcomplicating this by trying to use headers to pass back a result that can be passed more easily as part of the content. You even sort of realise this you're trying to use a PaginatedResponse in the Blazor client.
So instead of the API returning just a list, have a PaginatedResponse class in a shared library somewhere.. e.g.
/// <summary>
/// Paged result class
/// </summary>
/// <typeparam name="T"></typeparam>
public class PaginatedResponse<T>
{
public int TotalPages { get; set; }
public int Page { get; set; }
public List<T> Data { get; set; }
}
Your API then returns this
[HttpGet]
public async Task<ActionResult<PaginatedResponse<Country>>> GetAsync([FromQuery] Pagination paginationDto)
{
// ... query results here
var result = new PaginatedResponse<Country>()
{
Page = x,
TotalPages = totalPages,
Data = countrylist // from query
};
return result;
}
Your Blazor client can then use the same PaginatedResponse class and just use the standard GetFromJsonAsync method:
var result = await Http.GetFromJsonAsync<PaginatedResponse<Country>>("yourApiUri");
This is why I love Blazor!
This is the exactly answer for how search for answer:
in Server project, in startup.cs, in ConfigureServices method, add following code for CORS or update your CORS rule:
services.AddCors(options => options.AddPolicy(name: "WebApiProjectName or somthing", builder =>
{
builder.WithOrigins("http://localhost:xxxx") //xxxxx is server port
.AllowAnyMethod()
.AllowAnyHeader()
//.AllowCredentials() // its optional for this answer
.WithExposedHeaders("*"); // this is the code you need!
}));

CreatedAtRouteResult with swagger attribute

I have asp.net core web api. Where one of my controller returns CreatedAtRouteResult. How can I add swagger attribute for this method.
[HttpPost]
[SwaggerResponse(400, typeof(NotFoundResult))]
[SwaggerResponse(201, typeof(CreatedAtRouteResult))]
public async Task<IActionResult> Create([FromBody] SubscriptionDTO dto)
{
var issuedTo = (await _tokenService.Get()).IssuedTo;
SubscriptionDresult = await _subscriptionService.CreateAsync(dto, issuedTo.Id);
return result == null ? (IActionResult)NotFound(): CreatedAtRoute(new {id = result.Id}, result);
}
Can someone explain how to set the swagger response attribute from such type?
If you use ProduceResponseType attribute on your method, swagger will automatically pick it up and add it to the swagger.json document.
[HttpPost]
[ProducesResponseType(typeof(SubscriptionDTO), (int)HttpStatusCode.Created)]
[ProducesResponseType(typeof(void), (int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Create([FromBody] SubscriptionDTO dto)
{
var issuedTo = (await _tokenService.Get()).IssuedTo;
SubscriptionDTO result = await _subscriptionService.CreateAsync(dto, issuedTo.Id);
return result == null ? (IActionResult)NotFound(): CreatedAtRoute(new {id = result.Id}, result);
}
Note that you need to specify the actual DTO type returned for each response code in ProduceResponseType. Use void for no return body.

How to create an ASP.NET Core API controller action for HttpPost that can accept a request that has content of type MultipartFormDataContent

I am working on an ASP.NET Core 2.0 API in VS2017.
I want to create a controller action for an HTTP Post method that accept string and byte[] values that I will then use to create records in my SQL database.
From what I understand, if I want to post both string data and a byte[] that represents a file, I have to use MultipartFormDataContent as the type of content in the request from my client.
So, on the API controller action, how is that mapped? Can I have a DTO class in the API that has properties for both the string values and the byte[] value and have it passed into the API controller action via the [FromBody]UploadsDto dto
For example, have a DTO class like this...
public class UploadFileRecordForCreationDto
{
public int LocationId { get; set; }
public string FileName { get; set; }
public byte[] UploadedFile { get; set; }
}
Then have a controller action with this signature...
[HttpPost(Name = "CreateUploadFileRecord")]
public IActionResult CreateUploadFileRecord([FromBody]UploadFileRecordForCreationDto dto)
{
...
...
...
return CreatedAtRoute("GetUploadedFileFile", new { id = linkedResourceToReturn["Id"] }, linkedResourceToReturn);
}
And then have that API action accept a request created using something similar to what I am doing with this test console application on the client side;
static async Task CreateUploadFileRecordAsync()
{
httpClient.BaseAddress = new Uri("https://localhost:44369");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string relativeUrl = "/api/UploadFilesManager";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, relativeUrl);
HttpResponseMessage response = new HttpResponseMessage();
using (var content = new MultipartFormDataContent("--UploadTest"))
{
var values = new[]
{
new KeyValuePair<string,string>("LocationId","1"),
new KeyValuePair<string,string>("FileName","TestFile-01.txt"),
};
foreach (var keyvaluepair in values)
{
content.Add(new StringContent(keyvaluepair.Value, Encoding.UTF8, "application/json"), keyvaluepair.Key);
}
var fileContent = new ByteArrayContent(File.ReadAllBytes(#"C:\testfile-01.txt"));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue(DispositionTypeNames.Attachment)
{
Name = "UploadedFile",
FileName = "testfile-01.txt"
};
content.Add(fileContent);
request.Content = content;
response = await httpClient.SendAsync(request);
}
if (response.IsSuccessStatusCode)
{
string result = response.Headers.Location.ToString();
Console.WriteLine("Success:\n");
Console.WriteLine($"New Record Link: [{result}]\n");
}
else
{
Console.WriteLine($"Failed to create new UploadFile record. Error: {0}\n", response.ReasonPhrase);
}
}
If it doesn't just map to a DTO in the FromBody, can anyone provide an example of how to deal with this use case?

Return an image from asp.net web api core as IActionResult

What is the best way to return an image file as IActionResult while using asp.net web api core?
I tried returning a base64 string and it works fine. But not considered as efficient.
Is there a way using which we can return an image file object itself as IActionResult.
You can use the various overloads of the File() function in controllers that inherit from Controller or ControllerBase.
For example, you can do:
return File("~/Images/photo.jpg", "image/jpeg");
This uses a virtual path, other options include giving it a byte array or a Stream. You can also give a download file name as a third argument if that is needed.
[Route("getProductImage/v1")]
[HttpGet]
public async Task<IActionResult> getProductImage(GetProductImageQueryParam parammodel)
{
using (HttpClient client = new HttpClient())
{
MNimg_URL = MNimg_URL + parammodel.modelname;
HttpResponseMessage response = await client.GetAsync(MNimg_URL);
byte[] content = await response.Content.ReadAsByteArrayAsync();
//return "data:image/png;base64," + Convert.ToBase64String(content);
return File(content, "image/png", parammodel.modelname);
}
}
In .net core web api you can use the above code
here GetProductImageQueryParam is a class with input parameters
A File result is called FileContentResult in NET Core 3.x.
You can return image using return file with stream or bytes format or using its image path.
There are few overloaded methods for return File(//parameters); which you can use it in mvc controller's action method.
API Controller
[Route("api/[controller]")]
public class FileController : Controller {
//GET api/file/id
[HttpGet("{id}"]
public async Task<IActionResult> GetFile(string id) {
var stream = await {{//__get_stream_here__//}};
var response = File(stream, "application/octet-stream"); // FileStreamResult
return response;
}
}
or
var imageFileStream = System.IO.File.OpenRead("// image path");
return File(imageFileStream, "image/jpeg");
Hope this will help you.

Rest API Calls with RestSharp calling ASP.NET Web API

I'm currently testing out writing a RESTful API with ASP.NET Web API. I'm using RestSharp on a client to simulate different calls.
I want to submit an application ID query string, and the body should be a collection of type "Log". Every time, the application ID get's posted by the body received by the server is always NULL.
Code on the server:
public class LogsController : ApiController
{
public HttpStatusCode Post(Guid ID, [FromBody] List<Log> logs)
{
if (logs != null)
return HttpStatusCode.OK;
else
return HttpStatusCode.PreconditionFailed;
}
}
public class Log
{
public Guid ErrorId { get; set; }
}
Code on the client:
static void Main(string[] args)
{
var client = new RestClient("http://localhost:36146/api");
var json = JsonConvert.SerializeObject(new List<Log>()
{
new Log { ErrorId = Guid.NewGuid()}
});
var request = new RestRequest("Logs", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddParameter("ID", Guid.NewGuid(), ParameterType.QueryString);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json; charset=utf-8");
request.AddBody(json);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
Console.Read();
}
public class Log
{
public Guid ErrorId { get; set; }
}
I thought I got this working, however no matter what I do now the "logs" parameter on the server is always NULL.
I think I've found the issue.
RestSharp implicitly uses the JsonSerializer when populating the body of the request. As I was also called the Serializer I think it caused issues with the formatting.
I've removed that call to the serializer and now I'm receiving a 200 back from the server.
Happy days.