Binding là quá trình set values cho parameters khi Web API gọi controller action method.
Web API methods với các kiểu parameters khác nhau và cách customize binding process.
- Nếu parameter là simple type (int, bool, double, v.v.), Web API cố gắng lấy value từ URI (route data hoặc query string).
- Nếu parameter là complex type (Customer, Employee, v.v.), Web API Framework cố gắng lấy value từ request body.
Có thể thay đổi default behavior này bằng attributes [FromBody] và [FromUri].
FromUri (Mặc định cho Simple Types)
Nếu parameter là simple type, Web API lấy value từ URI.
.NET Primitive types: double, DateTime, GUID, string, và bất kỳ type nào convert được từ string.
Ví dụ
public Student Get(int id) { }
FromBody (Mặc định cho Complex Types)
Nếu parameter là complex type, Web API bind values từ message body.
Ví dụ
public Student Post(Employee employee) { }
[FromUri] Attribute
Ép Web API đọc complex type từ URI, thêm attribute [FromUri] vào parameter.
Dùng [FromUri] để force Web API lấy value của complex type từ QueryString.
Ví dụ
public Student Get([FromUri] Employee employee)
public HttpResponseMessage Get([FromUri] Employee employee) { ... }
[FromBody] Attribute
Dùng [FromBody] để lấy value của primitive type từ request body, ngược với default behavior.
Lưu ý: Không cho phép multiple [FromBody] trong single action.
Để force Web API đọc simple type từ request body, thêm [FromBody].
Trong ví dụ này, Web API dùng media-type formatter đọc value của name từ request body.
Ví dụ
public Student Post([FromBody] string name) { ... }
public HttpResponseMessage Post([FromBody] string name) { ... }
Binding Rules Summary
| Parameter Type | Default Source | Override với |
|---|---|---|
| Simple (int, bool, string, DateTime, Guid, Enum, decimal, etc.) | URI (Route data + Query String) | [FromBody] → Request Body |
| Complex (Class, Interface, Array, Collection) | Request Body (Media Formatter) | [FromUri] → URI (Query String) |
Ví dụ Chi Tiết
Simple Types từ URI
// GET /api/students?id=5&name=John&active=true
public IHttpActionResult Get(int id, string name, bool active) { ... }
// GET /api/students/5 (route data)
public IHttpActionResult Get(int id) { ... }
Complex Type từ Body (Default)
// POST /api/students
// Content-Type: application/json
// Body: {"Name": "John", "Age": 20}
public IHttpActionResult Post(Student student) { ... }
Force Complex Type từ URI ([FromUri])
// GET /api/students?name=John&age=20
public IHttpActionResult Get([FromUri] Student student) { ... }
// Model binder sẽ map query string properties đến Student properties
Force Simple Type từ Body ([FromBody])
// POST /api/students/name
// Content-Type: application/json
// Body: "John" (raw string, not JSON object)
public IHttpActionResult PostName([FromBody] string name) { ... }
// POST /api/students/age
// Body: 25 (raw number)
public IHttpActionResult PostAge([FromBody] int age) { ... }
Model Binding vs Formatter
| Đặc điểm | Model Binding ([FromUri]) | Media Formatter ([FromBody]) |
|---|---|---|
| Source | Query String, Route Data, Form Data | Request Body (JSON, XML, Form) |
| Mechanism | IModelBinder, ValueProvider | MediaTypeFormatter (Json, Xml, Form) |
| Complex Type Support | Có (flatten properties) | Có (full object graph) |
| Collection Binding | ?ids=1&ids=2&ids=3 | JSON Array: [1,2,3] |
Custom Model Binder
public class CommaSeparatedModelBinder : IModelBinder {
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) {
var valueProvider = bindingContext.ValueProvider;
var value = valueProvider.GetValue(bindingContext.ModelName);
if (value == null) return false;
var rawValue = value.AttemptedValue;
var numbers = rawValue.Split(',').Select(int.Parse).ToArray();
bindingContext.Model = numbers;
return true;
}
}
// Usage
public IHttpActionResult Get([ModelBinder(typeof(CommaSeparatedModelBinder))] int[] ids) { ... }
// Request: GET /api/values?ids=1,2,3,4,5
ASP.NET Core - Model Binding
// Attributes
[FromQuery] // Query string
[FromRoute] // Route data
[FromBody] // Request body
[FromHeader] // Request header
[FromForm] // Form data
[FromServices] // DI container
// Example
public IActionResult Get(
[FromRoute] int id, // Route: /api/{id}
[FromQuery] string filter, // Query: ?filter=abc
[FromBody] Student student, // Body: JSON
[FromHeader] string auth, // Header: Authorization
[FromServices] IStudentService service) { ... }