Tại sao chúng ta phải chỉ định FromBody và FromUri?


157

Tại sao FromBodyFromUricác thuộc tính cần thiết trong ASP.NET Web API`?

Sự khác biệt giữa việc sử dụng các thuộc tính và không sử dụng chúng là gì?


11
Chỉ cần đưa ra gợi ý về thời điểm có thể hữu ích khi sử dụng chú thích [FromBody]: Ví dụ, thực tế kém là gửi thông tin xác thực tĩnh như tên người dùng / mật khẩu như các tham số được mã hóa trong URL. Mặc dù mã hóa SSL có thể ngăn không cho bên thứ ba có thể có quyền truy cập đọc vào các tham số trong URL, nhưng vẫn còn thông lệ kém, vì những thông tin này có thể được lưu trữ trong nhật ký và bằng của trình duyệt, điều này chắc chắn không mong muốn. Trong trường hợp như vậy, người ta có thể sử dụng chú thích [FromBody], để buộc lưu trữ một tham số trong phần thân của thông điệp HTTP, giới thiệu mức cao
Chris

Câu trả lời:


193

Khi API Web ASP.NET gọi một phương thức trên bộ điều khiển, nó phải đặt các giá trị cho các tham số, một quá trình gọi là ràng buộc tham số .

Theo mặc định, API Web sử dụng các quy tắc sau để liên kết các tham số:

  • Nếu tham số là loại "đơn giản" , API Web sẽ cố gắng lấy giá trị từ URI . Các kiểu đơn giản bao gồm các kiểu nguyên thủy .NET (int, bool, double, v.v.), cộng với TimeSpan, DateTime, Guid, thập phân và chuỗi, cộng với bất kỳ loại nào có trình chuyển đổi loại có thể chuyển đổi từ chuỗi.

  • Đối với các loại phức tạp , API Web cố gắng đọc giá trị từ nội dung thư , sử dụng trình định dạng loại phương tiện.

Vì vậy, nếu bạn muốn ghi đè hành vi mặc định ở trên và buộc API Web đọc một loại phức tạp từ URI, hãy thêm [FromUri]thuộc tính vào tham số. Để buộc API Web đọc một loại đơn giản từ thân yêu cầu, hãy thêm [FromBody]thuộc tính vào tham số.

Vì vậy, để trả lời câu hỏi của bạn, nhu cầu của các thuộc tính [FromBody][FromUri]API trong Web chỉ đơn giản là ghi đè, nếu cần, hành vi mặc định như được mô tả ở trên. Lưu ý rằng bạn có thể sử dụng cả hai thuộc tính cho một phương thức điều khiển, nhưng chỉ cho các tham số khác nhau, như được trình bày ở đây .

rất nhiều thông tin trên web nếu bạn google "ràng buộc tham số web api".


2
@ user3510527: Bạn không phải sử dụng các thuộc tính này nếu bạn không muốn, miễn là bạn tuân theo hành vi mặc định. Nếu bạn muốn thay đổi hành vi mặc định, thì bạn cần sử dụng chúng.
djikay

1
nếu nó đang thực hiện hành vi mặc định của nó, thì tại sao chúng ta cần ovveride và chúng ta sẽ nhận được lợi ích gì nếu đề cập đến thuộc tính này?
Rajneesh

1
@ user3510527 Bạn không cần ghi đè. Bạn chỉ có thể sử dụng các hành vi mặc định. Một ví dụ mà ai đó có thể muốn ghi đè là nếu họ muốn cung cấp một số nguyên đơn giản trong phần thân của yêu cầu bởi vì theo mặc định, nó sẽ tìm thấy nó trong URI. Về cơ bản, bạn chỉ có thể để hành vi mặc định nếu bạn muốn hoặc bạn có thể ghi đè, đó chỉ là một tùy chọn bạn có. Tôi không hiểu sự nhầm lẫn là gì.
djikay

Tôi chỉ muốn biết quy trình làm việc nội bộ nếu chúng tôi sử dụng thuộc tính biểu mẫu, vì vậy trực tiếp nó sẽ nhận được giá trị và không kiểm tra bất kỳ uri hoặc formbody nào ...
Rajneesh

7
Tôi tự hỏi nếu người ta có thể tạo ra một thuộc tính được gọi là JustGetItphục vụ cho cùng một mục đích là thêm nhiều thuộc tính như [FromBody, FromQuery]vv
Các Muffin Man

93

Hành vi mặc định là:

  1. Nếu tham số là một nguyên thủy loại (int,bool,double, ...), cố gắng Web API để có được giá trị từ URI của yêu cầu HTTP.

  2. Đối với các loại phức tạp (ví dụ: đối tượng của riêng bạn Person:), API Web cố gắng đọc giá trị từ phần thân của yêu cầu HTTP.

Vì vậy, nếu bạn có:

  • một kiểu nguyên thủy trong URI, hoặc
  • một loại phức tạp trong cơ thể

... sau đó bạn không phải thêm bất kỳ thuộc tính nào ( [FromBody]cũng không phải[FromUri] ).

Nhưng, nếu bạn có một kiểu nguyên thủy trong cơ thể , thì bạn phải thêm [FromBody]vào trước tham số loại nguyên thủy trong phương thức điều khiển WebAPI của bạn. (Bởi vì, theo mặc định, WebAPI đang tìm kiếm các kiểu nguyên thủy trong URI của yêu cầu HTTP.)

Hoặc, nếu bạn có một loại phức tạp trong URI của mình , thì bạn phải thêm [FromUri]. (Bởi vì, theo mặc định, WebAPI đang tìm kiếm các loại phức tạp trong phần thân của yêu cầu HTTP theo mặc định.)

Các loại nguyên thủy:

public class UsersController : ApiController
{
    // api/users
    public HttpResponseMessage Post([FromBody]int id)
    {

    }
    // api/users/id
    public HttpResponseMessage Post(int id)
    {

    }       
}

Các loại phức tạp:

public class UsersController : ApiController
{       
    // api/users
    public HttpResponseMessage Post(User user)
    {

    }

    // api/users/user
    public HttpResponseMessage Post([FromUri]User user)
    {

    }       
}

Điều này hoạt động miễn là bạn chỉ gửi một tham số trong yêu cầu HTTP của mình. Khi gửi nhiều , bạn cần tạo một mô hình tùy chỉnh có tất cả các tham số của bạn như thế này:

public class MyModel
{
    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
}

[Route("search")]
[HttpPost]
public async Task<dynamic> Search([FromBody] MyModel model)
{
    // model.MyProperty;
    // model.MyProperty2;
}

Từ tài liệu của Microsoft về ràng buộc tham số trong API Web ASP.NET :

Khi một tham số có [FromBody], API Web sử dụng tiêu đề Kiểu nội dung để chọn một trình định dạng. Trong ví dụ này, loại nội dung là "application / json" và thân yêu cầu là một chuỗi JSON thô (không phải là một đối tượng JSON).Nhiều nhất một tham số được phép đọc từ nội dung thư.

Điều này sẽ làm việc:

public HttpResponseMessage Post([FromBody] string name) { ... }

Điều này sẽ không hoạt động:

// Caution: This won't work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Lý do cho quy tắc này là phần thân yêu cầu có thể được lưu trữ trong luồng không được đệm mà chỉ có thể được đọc một lần.


5
"Nhiều nhất một tham số được phép đọc từ nội dung thư" là thông tin đặc biệt hữu ích
Ryan

15

Chỉ cần thêm vào câu trả lời ở trên ..

[FromUri] cũng có thể được sử dụng để liên kết các loại phức tạp từ các tham số uri thay vì truyền tham số từ chuỗi truy vấn

Ví dụ:

public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }
}

[RoutePrefix("api/Values")]
public ValuesController : ApiController
{
    [Route("{Latitude}/{Longitude}")]
    public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}

Có thể được gọi như:

http://localhost/api/values/47.678558/-122.130989

12

Khi một tham số có [FromBody], API Web sử dụng tiêu đề Kiểu nội dung để chọn một trình định dạng. Trong ví dụ này, loại nội dung là "application / json" và thân yêu cầu là một chuỗi JSON thô (không phải là một đối tượng JSON).

Nhiều nhất một tham số được phép đọc từ nội dung thư. Vì vậy, điều này sẽ không hoạt động:

 // Caution: Will not work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Lý do cho quy tắc này là phần thân yêu cầu có thể được lưu trữ trong luồng không được đệm mà chỉ có thể được đọc một lần

Vui lòng truy cập trang web để biết thêm chi tiết: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.