Handling Posted Form Data in an API Controller
By FoxLearn 3/12/2025 3:54:47 AM 18
[Route("api/[controller]")] [ApiController] public class RegistrationController : ControllerBase { [HttpPost] public IActionResult Post([FromForm] string username, [FromForm] string email) { // Process registration data return Ok(new { Username = username, Email = email }); } }
You can send a POST request with form data to this endpoint as shown below.
POST /api/registration HTTP/1.1 Content-Type: application/x-www-form-urlencoded username=john_doe&[email protected]
The form data consists of key-value pairs (username=john_doe&[email protected]
). The framework matches the form keys with the parameter names (or model property names) to bind the data.
You can also map multiple form fields as separate parameters, map them to a model, or even process the form data directly.
Map Multiple Form Fields as Individual Parameters
For example, if your form has the fields Username
, Email
, and Password
, you can map them individually:
[Route("api/[controller]")] [ApiController] public class RegistrationController : ControllerBase { [HttpPost] public IActionResult Post([FromForm] string username, [FromForm] string email, [FromForm] string password) { // Process registration form data return Ok($"Registration successful for: {username} with email {email}"); } }
Here’s what the request to this endpoint might look like:
POST /api/registration HTTP/1.1 Content-Type: application/x-www-form-urlencoded username=john_doe&[email protected]&password=securePassword123
Note: When multiple form fields are included, the key-value pairs are separated by an ampersand (&
).
Mapping to a Model
Instead of binding form fields to individual parameters, you can map them to a model class.
[Route("api/[controller]")] [ApiController] public class RegistrationController : ControllerBase { [HttpPost] public IActionResult Post([FromForm] UserRegistration registration) { SaveToDatabase(registration); return Ok(); } // Other methods }
This maps the form data to the UserRegistration
class, which might look like this:
using System.ComponentModel.DataAnnotations; public class UserRegistration { [Required] public string Username { get; set; } [Required] [EmailAddress] public string Email { get; set; } [Required] [MinLength(8)] public string Password { get; set; } }
A request to this endpoint would look like:
POST /api/registration HTTP/1.1 Content-Type: application/x-www-form-urlencoded username=john_doe&[email protected]&password=securePassword123
When mapping to a model, the framework automatically maps the form fields to the model properties, and the comparison is case-insensitive (e.g., username
matches UserRegistration.Username
).
Handling Validation Errors
When mapping form data to parameters or a model, the framework performs validation and returns a 400 – Bad Request
if any validation fails.
For instance, if the Password
is too short or missing:
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-64ab197a56446c448095e9d3c3082c8b-a4255f612fce2e49-00", "errors": { "Password": [ "The Password must be at least 8 characters long." ] } }
Similarly, if a required field is missing (e.g., Email
), you’ll get:
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-d37111fc22168f42b5cbe4684eea9359-7a98c6fa7d623b4e-00", "errors": { "Email": [ "The Email field is required." ] } }
Error Response 415 – Unsupported Media Type
If you attempt to map a model without using the [FromForm]
attribute:
[HttpPost] public IActionResult Post(UserRegistration registration)
You’ll encounter a 415 – Unsupported Media Type
error:
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.13", "title": "Unsupported Media Type", "status": 415, "traceId": "00-cac8e6fd75525e40b3e2b61e0bc2008a-725c6cba45bde44d-00" }
To fix this, simply add the [FromForm]
attribute:
[HttpPost] public IActionResult Post([FromForm] UserRegistration registration)
Reading Form Data Directly
If you need to access form data directly without mapping it to parameters or a model, you can use HttpContext.Request.Form
. This gives you key-value pairs that can be processed as needed.
For example, How you might loop through the form data:
[HttpPost] public IActionResult Post() { foreach (var key in HttpContext.Request.Form.Keys) { var value = HttpContext.Request.Form[key]; // Process the form data } return Ok(); }
- Global exception event handlers in C#
- How to Add or overwrite a value in ConcurrentDictionary in C#
- How to Add a custom action filter in ASP.NET Core
- How to Get all classes with a custom attribute in C#
- How to Map query results to multiple objects with Dapper in C#
- How to Update appsettings.json in C#
- Injecting ILogger into Dapper Polly Retry Policy in C#
- Properly Disposing HttpContent When Using HttpClient in C#