Web API method return JSON data - c#

I am using ASP.net web API 2.0 and would like my method to return the data in JSON format only.
Please suggest the code changes for this below method from the API controller class.
public async Task<List<Partner>> GetPartnerList()
{
return await _context.Partners.Take(100).ToListAsync();
}

You can use the Json<T>(T content) method of the ApiController
public async Task<IHttpActionResult> GetPartnerList() {
List<Partner> data = await _context.Partners.Take(100).ToListAsync();
return Json(data);
}
refactor action to return IHttpActionResult abstraction, await the data and pass it to the Json method which returns a JsonResult.
This means that regardless of content negotiation, the above action will only return JSON data.

Related

Need to return attachment and JSON in get action method in API controller

I have a requirement that I need to send an attachment and JSON in a single get call.
[HttpGet]
[Route("IntakeByStudyIdandProjectNumber")]
[EnableCors("LocalhostPolicy")]
[EnableQuery]
public async Task<ActionResult> GetIntakebyStudyIdandProject()
{
IFormFile formFile = null;
return ok(await _manager.GetIntakeFormByIdandName(), formFile);
}
I am not sure which response type do I need to use to send both of them. For the files usually I use "FileContentResult" as the return type.

Web API HttpPost method always receives GET

I have a web api controller with a method
[HttpPost]
[Authorize]
[Route("[action]")]
public async Task<IActionResult> Authenticate(HttpRequestMessage msg)
{
//msg.Method is always GET
// msg.Content is null
}
I call it from my desktop application like this:
HttpClient client = new HttpClient(new HttpClientHandler(){AllowAutoRedirect = false});
foreach (var header in headers)
{
client.DefaultRequestHeaders.Add(header.Key, header.Value);
}
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
await client.PostAsync(requestUrl, content);
But in the web api method the property msg.Method is always GET and msg.Content is null
Is it sort of redirect or another intentional behavior that every request turns into GET?
I tried to change it to
[Authorize]
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> C2dSend([FromBody]string request)
{
return Ok();
}
but got 'BadRequest' after call.
The only thing that works is to replace string with dynamic:
[Authorize]
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> C2dSend([FromBody]dynamic request)
{
return Ok();
}
Only POST requests are routed to your action. You just looking at the wrong place - you are trying to bind body of your request to HttpRequestMessage instance. Obviously, you are passing something else here.
If you are looking for request details, use the Request property of controller. It is populated from contoller context which is passed to the controller during activation:
[Authorize]
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> C2dSend()
{
// Request.Method is POST here
return Ok();
}
But you don't need to use it to get request content. Let Asp.Net do this work for you - declare a model class which has the same properties as the serialized object which you are sending and model binder will do deserialization work for you:
[Authorize]
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> C2dSend(YourModel blah)
{
// model will be populated automatically from request body
return Ok();
}
Note: There is an easier way to send json requests. You can use PostAsJsonAsync extension from System.Net.Http.Formatting.Extension

HttpClient call to web api method with integer parameter Returns error 404

I really can't see what I am doing wrong here. I am trying to call a asp.net core web api method that accepts an integer via HttpClient but it returns a 404 error.
HospitalController (Web API)
[HttpGet("{id}")]
[Route("GetById")]
public JsonResult Get(int id)
{
return Json(_hospitalService.Get(id));
}
HospitalController (MVC)
protected string url = "http://localhost:5001/api/Hospital";
[HttpGet]
public async Task<IActionResult> Edit(int id)
{
if (id.Equals(0))
return StatusCode(404);
var accessToken = await HttpContext.GetTokenAsync("access_token");
client.SetBearerToken(accessToken);
HttpResponseMessage responseMessage = await client.GetAsync(url + "/GetById/" + id); //returns 404 error here.
if (responseMessage.IsSuccessStatusCode)
{
var responseData = responseMessage.Content.ReadAsStringAsync().Result;
var hospital = JsonConvert.DeserializeObject<Hospital>(responseData);
var hospitalVM = Mapper.Map<HospitalViewModel>(hospital);
return View(hospitalVM);
}
return View("Error");
}
I have a POST method in the same controller in MVC that works. But this GET method returns a 404 and I can't seem to know why.
There are two route templates being used in the api according to
[HttpGet("{id}")] //Matches GET api/Hospital/5
[Route("GetById")] //Matches GET api/Hospital/GetById
neither of which match what is being called
http://localhost:5001/api/Hospital/GetById/5
Http{Verb} attribute is usually used on RestFul APIs.
When building a REST API, it's rare that you will want to use [Route(...)] on an action method. It's better to use the more specific Http*Verb*Attributes to be precise about what your API supports. Clients of REST APIs are expected to know what paths and HTTP verbs map to specific logical operations.
Reference Routing to Controller Actions
update the route template on the web api to map to the desired route
[Route("api/[controller]")]
public class HospitalController : Controller {
//...code removed for brevity
//Matches GET api/Hospital/GetById/5
[HttpGet("GetById/{id:int}")]
public IActionResult Get(int id) {
return Ok(_hospitalService.Get(id));
}
}
Also HttpClient is meant to be used asynchronously, so the MVC controller would also need to be refactored as mixing blocking calls .Result can cause deadlocks
protected string url = "http://localhost:5001/api/Hospital";
[HttpGet]
public async Task<IActionResult> Edit(int id) {
if (id.Equals(0))
return StatusCode(404);
var accessToken = await HttpContext.GetTokenAsync("access_token");
client.SetBearerToken(accessToken);
HttpResponseMessage responseMessage = await client.GetAsync(url + "/GetById/" + id);
if (responseMessage.IsSuccessStatusCode) {
var responseData = await responseMessage.Content.ReadAsStringAsync();
var hospital = JsonConvert.DeserializeObject<Hospital>(responseData);
var hospitalVM = Mapper.Map<HospitalViewModel>(hospital);
return View(hospitalVM);
}
return View("Error");
}

Why does the Web API controller get null data from client through POST request?

I have an AngularJS app sending an object array to a Web API controller method through a POST request. On the server I have the following method definition:
[HttpPost]
[Route("Active")]
public async Task<IHttpActionResult> Post(IList<Media> mediaFiles)
{
try
{
foreach (var file in mediaFiles)
{
await Task.Factory.StartNew(() => PublicData.SetInactiveMedia(file.Id, file.Active));
}
return Ok();
}
catch (ArgumentException e)
{
return BadRequest(e.Message);
}
}
I use the $resource factory in order to interact with the server (but I have to mention that I have also tried with $http and no difference showed up). This is the method:
var activeMedia = $resource('/api/adminhotspotsmedia/active', { save: { method: 'POST' } });
var setActiveMedia = function (mediaFiles) {
activeMedia.save(mediaFiles);
}
The mediaFiles variable is an array of objects that absolutely match the Media model on the server.
In the Developer's Console I can see this Request Payload associated with the request:
So the array is trying to get to the server, but it cannot. The server gets a null value for the list of objects. I will add that I have tried using:
[FromBody] tag
dynamic instead of IList<Media>
IList<object> instead of IList<Media>
The problem persists. What could it be?
By default the model binder wont know what to do with the interface unless you have a custom model binder that knows what to expect and what the desired behavior is.
Alternatively you can use an actual List<Media>
[HttpPost]
[Route("Active")]
public async Task<IHttpActionResult> Post(List<Media> mediaFiles) { ... }
or array Media[]
[HttpPost]
[Route("Active")]
public async Task<IHttpActionResult> Post(Media[] mediaFiles) { ... }

How do i send a "forbidden" response in my Web API 2 solution?

I am making a web api to work with a legacy system. This web api should work in the same way as the old one. The security is to send a security token along with each call. This means that i need to check the token before serving data. I have a method like this:
public List<User> Get(string id, string securityToken)
{
//ValidateToken(securityToken);
return userRepository.LoadAll();
}
And in my method i would like the validateToken() method to return a "Forbidden" httpresponse if i cant validate it. How do i go around doing this?
You can use an HttpResponseMessage like so:
public HttpResponseMessage Get(string id, string securityToken)
{
var forbidden = true;
if (forbidden)
{
return this.Request.CreateResponse(HttpStatusCode.Forbidden);
}
return Ok(userRepository.LoadAll());
}
Using HttpResponseMessage allows you to return OK (an HTTP 200) with content, or an error.
IHttpActionResult:
return StatusCode(HttpStatusCode.Forbidden);
Or:
return Content(HttpStatusCode.Forbidden, "message");
HttpResponseMessage:
return this.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "message");
See this example if you would like a custom controller to have Forbidden() implemented just like BadRequest() or any other response.
https://stackoverflow.com/a/28361376/3850405
Typically you'd do the ValidateToken type call in an ActionFilterAttribute, returning the forbidden at that time, long before the Get method was called on the controller. You'd then apply that attribute to the controller or action method (or register it as a global action filter attribute if you need to authorize ALL calls).

Categories

Resources