Чому нам потрібно вказати FromBody та FromUri?


157

Чому потрібні атрибути FromBodyта FromUriатрибути у веб-API ASP.NET?

Які відмінності між використанням атрибутів і не використанням їх?


11
Просто для підказки, коли може бути корисним використання анотації [FromBody]: Це, наприклад, погана практика надсилати статичні облікові дані, такі як ім’я користувача / пароль, як параметри, закодовані в URL-адресі. Незважаючи на те, що шифрування SSL може завадити тому, що третя сторона може отримати доступ до читання параметрів у межах URL-адреси, вона все ще залишається поганою практикою, оскільки ці облікові дані можуть зберігатися в журналах браузера та дорівнювати, що, безумовно, не бажано. У такому випадку можна використовувати анотацію [FromBody], щоб змусити зберігати параметр у тілі повідомлення HTTP, вводячи високий
Кріс

Відповіді:


193

Коли веб-API ASP.NET викликає метод на контролері, він повинен встановлювати значення параметрів - процес, який називається прив'язка параметрів .

За замовчуванням Web API використовує такі правила для прив’язки параметрів:

  • Якщо параметр типу "простий" , Web API намагається отримати значення з URI . До простих типів належать примітивні типи .NET (int, bool, double та ін.), Плюс TimeSpan, DateTime, Guid, десяткові та рядкові, а також будь-який тип із конвертором типів, який може конвертувати з рядка.

  • Для складних типів Web API намагається прочитати значення з тіла повідомлення , використовуючи формат медіа-типу.

Отже, якщо ви хочете змінити вищезазначене поведінку за замовчуванням і змусити Web API прочитати складний тип з URI, додайте [FromUri]атрибут до параметра. Щоб змусити веб-API прочитати простий тип з тіла запиту, додайте [FromBody]атрибут до параметра.

Отже, щоб відповісти на ваше запитання, потреба атрибутів [FromBody]і [FromUri]атрибутів у веб-API - це просто перекрити, якщо необхідно, поведінку за замовчуванням, як описано вище. Зауважте, що ви можете використовувати обидва атрибути для методу контролера, але тільки для різних параметрів, як показано тут .

В Інтернеті є набагато більше інформації, якщо ви перейдете на Google "прив'язка параметрів web api".


2
@ user3510527: Вам не доведеться використовувати ці атрибути, якщо ви цього не хочете, дотримуйтесь поведінки за замовчуванням. Якщо ви хочете змінити поведінку за замовчуванням, тоді вам потрібно їх використовувати.
джикай

1
якщо він виконує свою поведінку за замовчуванням, то чому нам потрібно перемогти та які вигоди ми отримаємо, якщо ми згадали про цей атрибут?
Rajneesh

1
@ user3510527 Не потрібно переосмислювати Можна просто використовувати поведінку за замовчуванням. Один із прикладів, коли хтось може захотіти переосмислити, це якщо він хоче надати просте ціле число в тілі запиту, оскільки, за замовчуванням, він очікує, що він знайде його в URI. По суті, ви можете просто залишити поведінку за замовчуванням, якщо хочете або можете перемогти, це лише варіант, який у вас є. Я не розумію, в чому плутанина.
джикай

я просто хочу знати , внутрішній робочий процес , якщо ми використовуємо атрибут форми, так прямо він отримає значення і не перевірити будь-який УІДР або formbody ...
Раджниш

7
Цікаво, чи можна зробити атрибут, JustGetItякий називається, який служить тій самій цілі додавання декількох атрибутів, як [FromBody, FromQuery]і т
. Д.

93

Типова поведінка:

  1. Якщо параметр є примітивним типом ( int, bool, double...), Web API намагається отримати значення з URI запиту HTTP.

  2. Для складних типів (власний об'єкт, наприклад Person:) Web API намагається прочитати значення з тіла HTTP-запиту.

Отже, якщо у вас є:

  • примітивний тип в URI, або
  • складного типу в організмі

... тоді вам не доведеться додавати атрибути (ні те, ні [FromBody] ані [FromUri]).

Але, якщо у вас в організмі примітивний тип , вам доведеться додати [FromBody]перед своїм параметром примітивний тип у своєму методі контролера WebAPI. (Тому що за замовчуванням WebAPI шукає примітивні типи в URI запиту HTTP.)

Або, якщо у вас є складний тип у вашій URI , то ви повинні додати [FromUri]. (Тому що за замовчуванням WebAPI шукає складні типи в тілі запиту HTTP за замовчуванням.)

Первісні типи:

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

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

    }       
}

Складні типи:

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

    }

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

    }       
}

Це працює, поки ви надсилаєте лише один параметр у своєму HTTP-запиті. При надсиланні декількох вам потрібно створити власну модель, у якій є всі ваші параметри:

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;
}

З документації Microsoft щодо прив'язки параметрів у веб-API ASP.NET :

Коли параметр має [FromBody], веб-API використовує заголовок Content-Type для вибору форматера. У цьому прикладі тип вмісту - "application / json", а тіло запиту - це необроблена рядок JSON (не об'єкт JSON). Щонайменше один параметр дозволяється читати з тіла повідомлення.

Це має працювати:

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

Це не вийде:

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

Причиною цього правила є те, що тіло запиту може зберігатися в небуферизованому потоці, який можна прочитати лише один раз.


5

15

Просто доповнення до вищезазначених відповідей ..

[FromUri] може також використовуватися для прив'язки складних типів від параметрів uri замість передачі параметрів із запиту рядків

Для екс ..

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

Можна назвати:

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

12

Якщо параметр має [FromBody], веб-API використовує заголовок Content-Type для вибору форматера. У цьому прикладі тип вмісту - "application / json", а тіло запиту - це необроблена рядок JSON (не об'єкт JSON).

Щонайменше один параметр дозволяється читати з тіла повідомлення. Тож це не вийде:

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

Причиною цього правила є те, що тіло запиту може зберігатися в небуферизованому потоці, який можна прочитати лише один раз

Будь ласка, перейдіть на веб-сайт для отримання більш детальної інформації: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.