the values field is required - c#

Detail: I am trying to set up a simple get/post method inside asp.net controller and using postman to set if its set up correctly. I have looked for similar question on stackoverflow and they did not fixed my issue
Error: My Get method works fine but my post method giving an following error. Please see below postman:
debug: if I add a break line inside post method. it is never reaching to that break line
Code in asp.net
[ApiController]
[Route("[controller]")]
public class CoursesTakenController : Controller
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] {"value", "value" }
}
[HttpPost]
public Task<ActionResult<string>> Post([FromBody] string values)
{
return Ok(values);
}
}
I also tried this: but doesnt work
[HttpPost]
public async Task<IActionResult> Post([FromBody] string values)
{
return Ok();
}

You are posting a json object while the method expects a string. System.Text.Json (default json serializer used by ASP.NET Core) is pretty restrictive in JsonTokenType handling, so either post a string i.e. just "RandomText" (or encoded into string json object - {\"values\":\"asdasdasd\"}) or change action to accept an object:
public class Tmp
{
public required string Values { get; set; }
}
[HttpPost]
public async Task<ActionResult<string>> Post([FromBody] Tmp values)
{
...
}

Related

Cannot return HTML from a Controller

My code fails to return HTML from a Controller. The browser returns HTTP ERROR 500 - "This page does not work".
The Controller is written in .net core 3.1. Here is the code:
[ApiController]
[Route("")]
public class MyController : ControllerBase
{
[HttpGet]
public async Task<ActionResult<ContentResult>> GetInformation()
{
string s = #"<!DOCTYPE html><html><head><title>.....";
return base.Content(s, "text/html");
}
}
However, returning a plain string works: (using string instead of ContentResult. However, this string is not interpreted as HTML and is written directly to the browser)
[ApiController]
[Route("")]
public class MyController : ControllerBase
{
[HttpGet]
public async Task<ActionResult<string>> GetInformation()
{
string s = #"something";
return s;
}
}
public async Task<ActionResult<ContentResult>> GetInformation()
Because you declare that the action returns an ActionResult<ContentResult>, I expect that the ASP.NET Core serialisation process attempts to serialise the ContentResult you return as a JSON object. This is neither intended nor something the framework can manage.
Controller action return types in ASP.NET Core web API goes into the details, but a more typical method signature for your scenario would look like this:
public async Task<IActionResult> GetInformation()
You could also specify ContentResult, which implements IActionResult, if you'd prefer to do that:
public async Task<ContentResult> GetInformation()
IActionResult allows an action to return different responses in different situations, using e.g. BadRequest, Content, or Ok.

Handle WebApi Core methods with Id as string and int

I have two methods:
[HttpGet("{id}")]
public IActionResult GetTask([FromRoute] int id)
{
}
[HttpGet("{userId}")]
public IActionResult GetUserTask([FromRoute] string userId)
{
}
As you can see, i want to pass to my API routes like:
https://localhost:44365/Task/1
and
https://localhost:44365/Task/string
But my WebApi project cant handle it. When i pass route like this:
https://localhost:44365/Task/7dd2514618c4-4575b3b6f2e9731edd61
i get an 400 http and this response:
{
"id": [
"The value '7dd2514618c4-4575b3b6f2e9731edd61' is not valid."
]
}
While debugging, im not hitting any methods (when i pass string instead of int)
My question is, how to verload methods with one parameters with string or int? These methods do diffrent things
EDIT
When i pass something like:
https://localhost:44365/Task/dddd
I still get response with invalid id
You can define parameter type like [HttpGet("{id:int}")]. For more information refer below link.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2#route-constraints
Your actions should be like below.
[HttpGet("{id:int}")]
public IActionResult GetTask([FromRoute] int id)
{
}
[HttpGet("{userId}")]
public IActionResult GetUserTask([FromRoute] string userId)
{
}
Use like this
[HttpGet("{id}")]
public IActionResult GetTask([FromRoute] int id)
{
}
[HttpGet("User/{userId}")]
public IActionResult GetUserTask([FromRoute] string userId)
{
}
and while calling api with guid/string use
https://localhost:44365/Task/User/7dd2514618c4-4575b3b6f2e9731edd61

what is the difference between those 2 Post methods

am a bit confused about the difference between this 2 lines:
req.OpenReadStream();
and
Request.Form.Files.GetFile("FileContent").OpenReadStream()
here is what i know so far and correct me if am wrong, i know that they are both meant to read a file, and the first method accept file only, however the second accept file and a json value,,
but what i still dont understand is the difference in term of syntax
Here is a snippet from the post methods:
public IActionResult Post(IFormFile req)
{
req.OpenReadStream();
return Ok();
}
[HttpPost]
public IActionResult Post([FromForm] RequestModel req)
{
Request.Form.Files.GetFile("FileContent").OpenReadStream()
return Ok();
}
//....
public class RequestModel
{
public string FileContent { get; set; }
public string SomeRandomString { get; set; }
}
None. They both belong to IFormFile.
The only difference is how you're accessing the interface.
In your first example you're accessing it directly as it's passed into the constructor of your method.
In your second example you're accessing it from the Files collection of the HttpRequest by getting the file using GetFile method that returns the said interface.
As Panagiotis Kanavos said, the later can not be tested at all.

Update web api doesn't receive param?

I tried to call the update web api on Postman but it seems that it doesn't pass the id param to the asp.net core controller (asp.net core 2.0)
public class ShoppingCartController : BaseController
{
[HttpPut("{id}")]
[Route("api/ShoppingCart/UpdateShoppingCartItem")]
public IActionResult UpdateShoppingCartItem(long id)
{
return new NoContentResult();
}
}
You have to use [FromBody].
[HttpPut("{id}")]
[Route("api/ShoppingCart/UpdateShoppingCartItem")]
public IActionResult UpdateShoppingCartItem([FromBody]long id)
{
return new NoContentResult();
}
In Postman you must use a simple number.
Replace:
{
"id":87908908
}
with
87908908
Default behaviour of param parsing: From Url.
Use [FromBody] before your method param to let asp parse this param from the Body.
Can you try changing method UpdateShoppingCartItem to the following:
public IActionResult UpdateShoppingCartItem([FromBody] long id)
HttpPut now accepts the route as parameter, so you can combine your attributes.
public class ShoppingCartController : BaseController
{
[HttpPut("api/ShoppingCart/UpdateShoppingCartItem")]
public IActionResult UpdateShoppingCartItem(long id)
{
return new NoContentResult();
}
}
The model binder should infer the value of id from the body.
Using [HttpPut("{id}")] would mean that a put request to localhost:44342/65465 would be a valid action.

Web API routing with DTO object - C#

I have two projects, one is SPA and the other one is ASP.NET aspx project.
Normally those two projects communicate with each other via web API.
There is a running method like this (from SPA to ASP.NET)
[HttpPost]
[Route("DenyInvoice/{approvalId:long}")]
public IHttpActionResult DenyInvoice(long approvalId)
{
string exMsg = "";
if (DenyInvoice(approvalId, this.UserId, this.Email, out exMsg))
return Ok();
return BadRequest(exMsg);
}
This method works as I wanted, but I want to write a method that accepts a DTO variable like;
[HttpPost]
[Route("InvoiceDetailUpdate/{invoices : invoiceDetailDtoModel}")]
public IHttpActionResult InvoiceDetailUpdate(invoices : invoiceDetailDtoModel)
{
....
}
Is it possible? How should I do this?
Can you help?
Thank you..
Use [FromBody] to pass in the POST parameter. See https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-web-api#implement-the-other-crud-operations for more details.
[HttpPost]
[Route("InvoiceDetailUpdate")]
public IHttpActionResult InvoiceDetailUpdate([FromBody]InvoiceDetailDtoModel invoices)
{
....
}
You want to retrieve parameter via post so there is no required for get parameter routing.
[HttpPost]
[Route("InvoiceDetailUpdate")]
public IHttpActionResult InvoiceDetailUpdate(InvoiceDetailDtoModel invoices)
{
....
}
Also, be careful with the name convention of a class.
In the following code, you can use like this :
public class BooksController : ApiController
{
[Route("api/books")]
public IEnumerable<Book> GetBooks() { ... }
[Route("api/books/{id:int}")]
public Book GetBook(int id) { ... }
[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }
}
Now , you can see this link attribute-routing-in-web-api-2
and change your code to above figure
[Route("api/YourController/InvoiceDetails")]
public IHttpActionResult InvoiceDetailUpdate(InvoiceDetails invoiceDetailsDto)

Categories