What is the function of [FromBody] Attribute in C#? - c#

Is there a function of [FromBody] attribute? I mean, when I use it for example:
public async Task SetUser([FromBody]User user)
and when I use:
public async Task SetUser(User user)
The server get the same object without problems, so, it's necessary set it, or I can remove it without worries?
Grettings!

User is a complex type, so by default the server will try to resolve it from the request body. If you had a simple type -- e.g.
public async Task SetUser(string userId)
the server would try to resolve the value via URL binding. You can override that behaviour by specifying
public async Task SetUser([FromBody] string userId)
I usually leave [FromBody] in the signature simply for the sake of readability.

There are two ways parameters can be passed to the server - via URI, or as part of the request body.
When data are passed in URI, they become query string - e.g. http://server.com/something?userId=5. This will be handled by the action method with int userId argument.
When data are passed in request body, then you cannot see them in the URI - it would be http://server.com/something, for example. Parameters are then passed as name-value pairs inside the request body.
However, in order to pass anything through body, there must be the body, and GET request normally doesn't have request body (it can have it, technically, but I'm not sure if it's used to pass parameters to GET action methods). You would usually expect arguments to be adorned with the FromBody attribute in POST action methods. Likewise, you would usually expect GET actions to receive arguments through URI, which is more in line with the purpose of the GET method.
You can specify either FromUri or FromBody to control behavior. There is also BindModel attribute which lets you define custom binding.

Related

get parameters from the request body along with a model

how to get the devId from the body, even using [FromBody], it keeps identifying the devId as a query
public async Task<ActionResult<Module>> PostModule([FromBody]Module module, long devId){}
You can only have 1 argument with a FromBody applied.
From the documentation
Don't apply [FromBody] to more than one parameter per action method. Once the request stream is read by an input formatter, it's no longer available to be read again for binding other [FromBody] parameters.
If you want that devId being read from the body, you'll have to include that one as e.g. a property in your Module class.

Web API model validation based on paramters

I have API like this , what i want his
When i call with out any parameters
http//localhostcustomer/employes/ it should return
StatusCode(StatusCodes.Status404NotFound)
And if pass with invalid parameters http//localhostcustomer/employes/customerid=abcsd&employedid=yyyy it should return
StatusCode(StatusCodes.Status400BadRequest);
how to do model validation for this
[Route("customer/employes")]
Public class testcontroller : controller
public List<Emplyees> get( [Required]int customerid, [Required]int employedid)
{
if (ModelState.IsValid)
return OK
else
StatusCode(StatusCodes.Status400BadRequest);
}
since you dont actually pas a model u dont realy get to place the validation on something since u just pass loose parameters.
u could create a method or class that validates your input parameters like
IsValid(CustomerId,EmployedId) return Ok()
Or modify the current ModelState.IsValid so
ModelState.IsValid(CustomerId,EmployedId) return Ok()
Since it seems that your are trying to create a Get request with Required parameters it might be interesting to format this as a proper REST call so your path looks like
/customer/[CustomerId]/employes/[employedId]
Without parameters - Not Found
If you haven't registered (either explicitly or implicitly via attributes) the route /employees then ASP.NET will not find a handler for that request that's why by default it will return with 404.
With malformed parameters - Bad Request
That's a bit more tricky. Whenever you have a route with parameters then you can define their types as well. By default if the request contains the route parameter, which can't be converted into that specific type then ASP.NET will not call your handler, rather than it will try to find a better route for that.
Request: /employees/123info
[Route("customer/employees")]
public List<Employee> Get( [Required]int someParameter) {
If you want to catch malformed requests as well, then you have to use string parameters and try to apply the conversion logic manually:
[Route("customer/employees")]
public IActionResult Get(string someParameter) {
bool isItAValidParameter = int.TryParse(someParameter, out var validParameter):
if (!isItAValidParameter)
...
You are not passing a model as your parameter, hence validating a model makes no sense. You need to validate your loose parameters explicitly. In case of invalid parameters:
Request: /employes/customerid=abcsd&employedid=yyyy
By default, the api will return status 400 - Bad Request Error.
In case of without any parameters:
you will get HTTP ERROR 404 - Page can't be found
I would take a look at FluentValidation, which is a popular .NET library for building strongly-typed validation rules.
You can create a custom validator that checks your controller method parameters and that creates a response accordingly.
Something along the lines of:
var validator = new CustomerEmployeeValidator();
var validation = validator.Validate(someparameter);
if (!validation.IsValid)
return BadRequest(validation.Errors);
On how to create the validator, you should look into:
https://fluentvalidation.net/
As a side note, when the input parameter is incorrect, you should always return a BadRequest StatusCode instead of a NotFound StatusCode.
A NotFound StatusCode is typically used when you are searching for specific data externally, and is not found in that repository.

API with optional query string is losing the route value

I want to have a WebAPI path that takes an Id, but also, an optional query.
So, usually, the client will send:
http://localhost:49487/api/template/5b31b31c-ecd9-4e7a-bcdb-1c263399c86f
But sometimes, I need to return a bit of extra details in the payload. So I want them to send:
http://localhost:49487/api/template/5b31b31c-ecd9-4e7a-bcdb-1c263399c86f?IncludePreview=true
My .Net Web API Controller enpoint is defined like this, and handles the first case.
[Route("{Id}"), HttpGet]
public IActionResult GetTemplate(Guid Id, bool IncludePreview = false)
But as soon as I sent the second version, with the query string, the api controller fires (I have a breakpoint on it), but, Id is always Guid.Empty.
How can I have my API method accept both versions? Or do I need to create a separate endpoint for both versions?
You are assigning the Include Preview Boolean value as a fixed value. So event though your call catches the IncludePreview=true in GetTemplate method ,it get reassign. Please try to use a nullable Boolean with 'null' as assigned value.
public IActionResult GetTemplate(Guid Id, bool? IncludePreview=null)

WebApi - UrlHelper.Route to GET with [FromUri] object parameter

I have an API action defined as the following:
[Route(Name="GetMembersTest"), HttpGet, ResponseType(typeof(MemberHeadersDto))]
public IHttpActionResult GetMembers[FromUri]MemberFilterDto filter, [FromUri]PagingOptionsDto paging)
This method works as expected, routing and all, requests are flowing through just fine. However, I'd like to supply a "NextUri" for paging so that the caller can just keep following NextUri until it is null to get all the results. I have to send back a uri to the same action, 1 page ahead, if that makes sense.
So I tried using UrlHelper.Route. This route is named "GetMembers" for the purpose of this example.
NextUri = Url.Route("GetMembers", new { filter, paging });
The problem is that instead of getting something like
/v1/members?filter.q=&filter.otherproperty=&paging.count=10&paging.startRow=11
I get
/v1/members?filter=WebApi.Models.MemberFilterDto&paging=WebApi.Models.PagingOptionsDto
It looks like UrlHelper.Route doesn't support complex types in the [FromUri] parameter of a GET Request. Is there anything I can do to get this functionality? My workaround right now is to take in all the Dto properties as individual parameters then build my Dtos from them on the server. This isn't ideal because if I ever add any more options I'd have to add more parameters to the action, which also makes the route value dictionary more fragile as well because it has to match with the method signature in UrlHelper.Route(routeName,routeValues).
Unfortunately, there is no way to pass in complex object to routing. Instead, you will need to pass in the simple properties individually.
I was not able to find a way to extend Url.Route, but that would be/have been your best option.

WebAPI routing to a function with multiple optional parameters

I have the following function header in WebAPI controller declared as route:
[Route("page/{page}/{cityfilter?}/{statefilter?}/{organizationfilter?}")]
public IEnumerable<Contact> GetContact(int page, string cityfilter = null, string statefilter = null, string organizationfilter = null)
{
...
}
The issue here is that I'd wish that every parameter is optional, so I'd want to make a request that has either a cityfilter, a statefilter, an organization filter, two of them or three of them, and then be processed and router by this function, but I have no clue about how I can build the URI so that, for instance, this route works for just the statefilter.
How can I do that in WebAPI? How should I call the resource address from, for instance, a Jquery Ajax call?
Thank you.
Since the parameters are simple types (strings), they can be bound either from the route data (URL path) or the query string. So you can move the optional parameters to the query string and have your route only match the page parameter.
[Route("page/{page}")]
Here's an example of a URL that you would use to call this action from the browser or from an AJAX call:
www.yourapidomain.com/page/1?cityfilter=aCityFilterString&statefilter=aStateFilterString&organizationfilter=anOrganizationFilter
You may of course omit any of the optional parameters or change their order.
The action method signature can remain as it is in your example.
For more information, you can have a look at parameter binding ASP.NET Web API.

Categories