Почему мы должны указывать FromBody и FromUri?


157

Почему FromBodyи FromUriатрибуты , необходимые в ASP.NET Web API`?

Каковы различия между использованием атрибутов и неиспользованием их?


11
Просто для подсказки, когда может быть полезно использовать аннотацию [FromBody]: например, плохая практика - отправлять статические учетные данные, такие как имя пользователя / пароль, в качестве параметров, закодированных в URL. Несмотря на то, что SSL-шифрование может помешать третьей стороне получить доступ для чтения к параметрам в URL-адресе, это все равно остается плохой практикой, поскольку эти учетные данные могут храниться в журналах браузера и равнозначно, что определенно нежелательно. В таком случае можно использовать аннотацию [FromBody], чтобы принудительно сохранить параметр в теле HTTP-сообщения, введя высокий
Chris

Ответы:


193

Когда ASP.NET Web API вызывает метод на контроллере, он должен установить значения для параметров, процесс, называемый привязкой параметров .

По умолчанию веб-API использует следующие правила для привязки параметров:

  • Если параметр имеет «простой» тип , Web API пытается получить значение из URI . К простым типам относятся типы примитивов .NET (int, bool, double и т. Д.), А также TimeSpan, DateTime, Guid, decimal и string, а также любой тип с преобразователем типов, который может преобразовывать строки.

  • Для сложных типов Web API пытается прочитать значение из тела сообщения , используя средство форматирования медиа-типа.

Поэтому, если вы хотите переопределить вышеуказанное поведение по умолчанию и заставить Web API считывать сложный тип из URI, добавьте [FromUri]атрибут к параметру. Чтобы заставить Web API читать простой тип из тела запроса, добавьте[FromBody] атрибут к параметру.

Таким образом, чтобы ответить на ваш вопрос, то потребность [FromBody]и [FromUri]атрибуты в Web API является просто переопределить, если это необходимо, поведение по умолчанию , как описано выше. Обратите внимание, что вы можете использовать оба атрибута для метода контроллера, но только для разных параметров, как показано здесь .

В Интернете можно найти гораздо больше информации, если вы воспользуетесь «привязкой параметров веб-API».


2
@ user3510527: Вы не должны использовать эти атрибуты, если не хотите, если вы следуете поведению по умолчанию. Если вы хотите изменить поведение по умолчанию, то вам нужно их использовать.
Джикай

1
если он выполняет свое поведение по умолчанию, то зачем нам нужно повторять и какие преимущества мы получим, если упомянем этот атрибут?
Раджниш

1
@ user3510527 Вам не нужно переопределять. Вы можете просто использовать поведение по умолчанию. Один из примеров, где кто-то может захотеть переопределить, это если он хочет предоставить простое целое число в теле запроса, потому что по умолчанию он ожидает найти его в URI. По сути, вы можете просто оставить поведение по умолчанию, если хотите, или вы можете переопределить, это просто опция, которая у вас есть. Я не понимаю, в чем путаница.
Джикай

я просто хочу знать внутренний рабочий процесс, если мы используем атрибут формы, поэтому он напрямую получит значение, а не проверит uri или formbody ...
Rajneesh

7
Интересно, можно ли создать атрибут с именем, JustGetItкоторый служит той же самой цели, добавив несколько атрибутов, например, и [FromBody, FromQuery]т. Д.
The Muffin Man

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 по привязке параметров в ASP.NET Web API :

Если параметр имеет значение [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.