Model Binding in ASP.NET Core
Understand how ASP.NET Core binds request data to action parameters.
By EMEPublished: February 20, 2025
asp.net coremodel bindingdata bindingrouting
A Simple Analogy
Model binding is like an automatic mail sorter. It takes incoming request data and automatically places it into the right parameters.
Why Model Binding?
- Automation: No manual parsing
- Type safety: Automatic conversion
- Validation: Built-in validation
- Convenience: Less code
- Flexibility: Multiple sources
Binding Sources
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
[HttpGet("{id}")]
public ActionResult GetOrder(
int id, // From route
[FromQuery] string status, // From query string
[FromHeader] string authorization, // From headers
[FromBody] OrderFilter filter) // From body
{
return Ok();
}
[HttpPost]
public ActionResult Create(
[FromForm] OrderDto orderData, // From form
[FromServices] IOrderService service) // From DI
{
return CreatedAtAction(nameof(GetOrder), new { id = 1 });
}
}
Custom Model Binder
public class DateTimeModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
return Task.CompletedTask;
if (DateTime.TryParse(valueProviderResult.FirstValue, out var date))
{
bindingContext.Result = ModelBindingResult.Success(date);
}
else
{
bindingContext.ModelState.AddModelError(modelName, "Invalid date format");
}
return Task.CompletedTask;
}
}
// Register
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new BindingSourceMetadataProvider(
typeof(DateTime),
new DateTimeModelBinder()));
});
Complex Types
public class CreateOrderRequest
{
public string CustomerId { get; set; }
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public string ProductId { get; set; }
public int Quantity { get; set; }
}
// Binds automatically
[HttpPost]
public ActionResult Create(CreateOrderRequest request)
{
// request.Items are populated from JSON
return Ok();
}
Validation
public class CreateOrderRequest
{
[Required]
[StringLength(50)]
public string CustomerId { get; set; }
[Required]
[MinLength(1)]
public List<OrderItem> Items { get; set; }
}
[HttpPost]
public ActionResult Create(CreateOrderRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// request is valid
return Ok();
}
Best Practices
- Use attributes: Make bindings explicit
- Validate early: Check ModelState
- Specify sources: Avoid ambiguity
- Document parameters: Swagger generation
- Test binding: Verify conversions work
Related Concepts
- Dependency injection
- Routing
- Action filters
- Validation
Summary
Model binding automatically converts request data into action parameters. Use FromRoute, FromQuery, FromBody, and FromForm attributes to control sources.