Apply [FromBody] attribute to all controller actions in .net core - asp.net-core

Having a simple .NET Core API with your models posted as JSON in request body, how to have [FromBody] attribute applied to all controller methods?
[Route("api/simple")]
public class SimpleController : ControllerBase
{
[HttpPost]
public IActionResult Post([FromBody] MyRequest request)
{
return Ok();
}
}
If I remove the [FromBody] attribute, all model properties will be null.

If you POST your model inside the body with Content-Type: application/json then you have to tell the ModelBinder to read the model from body by applying [FromBody] attribute.
But adding [FromBody] to all of your API actions makes you feel bad.
Just apply the [ApiController] to your controller and then you don't need [FromBody] anymore.
Microsoft Doc definition of [ApiController]
Indicates that a type and all derived types are used to serve HTTP API responses.
Controllers decorated with this attribute are configured with features and behavior targeted at improving the developer experience for building APIs.
So this works without [FromBody] in ASP.NET Core 2.1 and above
[Route("api/simple")]
[ApiController]
public class SimpleController : ControllerBase
{
[HttpPost]
public IActionResult Post(OrderRequest request)
{
return Ok();
}
}

Related

How to resolve Security code scan SCS0016 in API controller

We have implemented weather API controller to update weather data and inherited ControllerBase in API controller with APIController action filter like below and enabled security code scan.
using Microsoft.AspNetCore.Mvc;
namespace SampleApiApplication.Controllers
{
[ApiController]
public class WeatherForecastController : ControllerBase
{
[HttpPost]
[Route("UpdateWeatherDetails")]
public IEnumerable<WeatherForecast> PostWeatherDetails(WeatherForecast weatherForecast)
{
// Some lines of code to implement
}
}
}
I can be able to post Json content data, but I Could not able to post data with content type as application/x-www-form-urlencoded in UpdateWeatherDetails API.
To resolve the above issue, I have used [FromForm] attribute to post form data like below, now I am able to post form data and Json data. But I have faced security warning SCS0016.
using Microsoft.AspNetCore.Mvc;
namespace SampleApiApplication.Controllers
{
[ApiController]
public class WeatherForecastController : ControllerBase
{
[HttpPost]
[Route("UpdateWeatherDetails")]
[Consumes("application/json")]
public IEnumerable<WeatherForecast> PostWeather([FromBody] WeatherForecast weatherForecast)
{
return PostMethod(weatherForecast);
}
[HttpPost]
[Route("UpdateWeatherDetails")]
public IEnumerable<WeatherForecast> PostWeatherDetails([FromForm] WeatherForecast weatherForecast)
{
// Some lines of code to implement
}
}
}
I thought after adding FromForm attribute only facing security warning and removed it, now no security warning, but I am unable get data binding to parameter. Now,  I have removed [ApiController] attribute and tried to post form data, Now I am able to post form data.
But I am again getting Security warning** SCS0016 **for that method.
How to resolve the above Security issue and get data send with application/x-www-form-urlencoded working?

How can I add links to other controller methods in generated OpenAPI specs using attributes in ASP.NET Core?

I am using SwaggerGen to generate an OpenAPI spec for our API, and would like to add links between certain endpoints.
OpenAPI 3.0 Links
Is there a way to add an attribute to the controller method that links to another controller method?
For example, if I currently have something like
[HttpPost]
[Route("~/users")]
[ProducesResponseType(typeof(ResponseObject<UserId>), StatusCodes.Status200OK)]
public async Task<IActionResult> CreateUser(...)
{
// Create user
}
[HttpGet]
[Route("~/users/{userId}")]
[ProducesResponseType(typeof(ResponseObject<User>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetUser(...)
{
// Get newly created user
}
Could I somehow link them like
[HttpPost]
[Route("~/users")]
[ProducesResponseType(typeof(ResponseObject<UserId>), StatusCodes.Status200OK)]
[Link(nameof(GetUser), "UserId")]
public async Task<IActionResult> CreateUser(...)
{
// Create user
}
[HttpGet]
[Route("~/users/{userId}")]
[ProducesResponseType(typeof(ResponseObject<User>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetUser(...)
{
// Get newly created user
}
to generate the "links" field as shown in the OpenAPI 3.0 spec linked above?

In Asp Net Core, Do I have to put the Attribute of [Authorize] for both Get and Post Method?

In the controller, normally we have a Get and a Post methods
for example:
[HttpGet]
[Authorize(Policy = "AdminMs")]
public async Task<IActionResult> MSCreate()
{
}
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Policy = "AdminMs")]
public async Task<IActionResult> MSCreate(empolyee)
{
}
Do I have to set the Authorize Attribute for both methods or only for HttpGet?
If you need only authorized access to any of the end points, you have to use [Authorize] on whichever method that corresponds to that endpoint. Having it on one method does not mean that it will restrict the other method even if they have similar method names.

How do I get Route attribute to work in .net core api?

So I added a controller to a blank asp.net CORE Api.
public class IsAliveController : ControllerBase
{
[HttpPost]
[HttpGet]
[Route("isalive")]
public object Get()
{
return "I'm alive";
}
}
Then I try to access it via https://localhost:44361/isalive
and I get no response. Do I need to make some modifications to my Startup.cs?
First why have you declared your method both as a get and a post request? you can remove the post attribute.
By default your routing must start with your controller name, add this:
[Route("[controller]")]
[ApiController]
public class IsAliveController : ControllerBase
{
[HttpGet]
public object Get()
{
return "I'm alive";
}
}
Now when you call https://localhost:44361/isalive you will receive the expected response.
There are two solutions to your problem:
#1 Your controller Name is IsAlive and you have added a route attribute on your action method as isAlive, so this would work only if you call using this Url
https://localhost:44361/isalive/isalive
#2 Remove the Route attribute from the action method
public class IsAliveController : ControllerBase
{
[HttpGet]
public object Get()
{
return "I'm alive";
}
}
and you will be able to access using Url
https://localhost:44361/isalive
Found the issue. The template I choose (using Visual studio 2019) was:
Asp.net core web app > Web Application
The startup file in this template is missing a line that I needed to add:
app.UseEndpoints(endpoints =>
{
//Add this line
endpoints.MapControllers();
});
After adding that line the endpoint works without any changes to the controller.

ASP.Net Core required parameter binding fails to fail using FromBody

I'm developing an Asp.Net Core API.
My controller declaration
[ApiController]
public class BarController : Controller
{
...
}
My endpoint looks like this
[HttpPost, Route("bars")]
public async Task<ActionResult> DoAsync(
[FromBody] UpdateBars command)
{
// Do something with the command
return Ok(result);
}
The command looks like this
public class UpdateBars
{
[Required]
public IEnumerable<string> Ids { get; set; }
// ... more properties
}
Compatibility level is set to 2.1
public IServiceProvider ConfigureSharedServices(IServiceCollection services)
{
// ...
services.AddMvc()
.AddControllersAsServices()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// ...
}
Old question: I'd expect this to return a 400 bad request with a missing Ids parameter, but it fails to return the binding error.
What am I doing wrong?
Updated question: I'd expect this to return a 400 bad request with a missing or empty Ids parameter. The response is as expected if the parameter is missing (null), but returns 200 ok if it is an empty collection.
Is it possible to change something so that I get a bad request when the parameter is present but empty?
You probably didn't put a [ApiController] attribute on your controller.
By default the validation is not 'automatic'.
If you don't want to put that attribute on your controller, you will have to validate the model yourself, in following way:
[HttpPost, Route("bars")]
public async Task<ActionResult> DoAsync(
[FromBody] UpdateBars command)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Do something with the command
return Ok(result);
}
You have more controll in that way, but if you just need to return a BadRequest with the model state, it will happen automatically if you put the [ApiController] on the controller.
Also in that case it will mark all action parameters as [FromBody], so putting that attribute on params is not needed
You should add the [ApiController] attribute. In that case, an automatic HTTP 400 response containing error details is returned when model state is invalid. For more information, see Automatic HTTP 400 responses. Automatic HTTP 400 responses.