Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Parameter Binding trong C# ASP.NET WebAPI

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) { ... }