Как закалялся код...: ASP.NET Web API массив в значении параметра запроса HTTP GET. Привязка параметров из URL - FromUri binding.

воскресенье, 22 марта 2015 г.

ASP.NET Web API массив в значении параметра запроса HTTP GET. Привязка параметров из URL - FromUri binding.

Массив в параметре Get запроса


Обычно в GET запросах .NET Web API используются простые параметры запроса типа int id, string filter, string query и т.д. При использовании простых типов привязка параметров для GET запросов происходит без проблем. Если вам понадобится выполнить запрос к вашему приложению Web API передав в качестве параметра GET массив значений или полноценный объект (и на серверной вы хотите получить сразу объект), то потребуется использование специального биндера.

Допустим есть javascript get запрос на стороне клиента, где параметром передается массив значений типа integer:

// Используем jquery
var ids = [2,3,4,5];
$.getJSON("@Url.Content("api/Values")", { ids: ids })
.done(function (result) {
    $(".result").text(result);
});

Этот код формирует такой запрос:
GET   /api/Values?ids[]=2&ids[]=3&ids[]=4&ids[]=5

Если просто прописать нужные типы данных в действие контроллера (массив):

 public string Get(int[] ids)
 {
    return "Success: " + string.Concat(ids);
 }

То на стороне сервера вы получите ids = null;

Принцип работы Web API


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

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

Настройка привязки сложных типов в GET запросе


Вообще для сложных типов данных, не рекомендуется использоваться GET запросы. Ключевым принципом HTTP является то, что ресурсы направляются в теле сообщения, используя согласование содержимого для указания представления ресурса. Именно с этой целью были разработаны media-type formatters.

Но все же в .net есть реализация привязки из URI. Для этого к требуемому параметру со сложным типом данных нужно подставить атрибут [FromUri] или [ModelBinder]:

 public string Get([FromUri]int[] ids)
 {
    return "Success: " + string.Concat(ids);
 }

Теперь в ids будет ожидаемый массив значений.

Привязки [FromUri] и [ModelBinder]


FromUriAttribute просто является наследником от ModelBinderAttribute, предоставляя более короткую (и более понятную для разработчика) команду для Web API, чтобы брать определенные параметры из URI, используя ValueProviders, определенные в IUriValueProviderFactory. Сам атрибут не может иметь наследников.

[ModelBinder] предоставляет вам возможность реализации собственной логики преобразования входящих значений запроса в типы данных CLR (тема для отдельной статьи).

Другие примеры использования атрибута привязки [FromUri]


Сложный тип:
public class TableFilter 
{
    public int Page { get; set; }
    public int PageSize { get; set; }
    public IList<SortType> Sort {get; set;}
}

public HttpResponseMessage Get([FromUri]TableFilter filter) {}
 
GET /table?page=1&pagesize=60&sort=field|asc

Коллекции типа List:

GET /Values?items=first&items=second&items=third
 
public string Get([FromUri]List items) {}


Коллекции типа ключ-значение:

GET /values?key=stringkey&value=stringvalue
 
public string Get([FromUri]KeyValuePair id) {}

Привязка параметров из URI по умолчанию


Можно настроить Web API на обработку параметров GET запросов c помощью [FromUri] по умолчанию, для этого следует создать наследника от DefaultActionValueBinder:


public class MyActionValueBinder : DefaultActionValueBinder
{
    protected override HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter)
    {
       if(parameter.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Get)){
          return parameter.BindWithAttribute(new FromUriAttribute());
       }
       return base.GetParameterBinding(parameter);
    }
}


И заменить обработчик привязок по умолчанию в конфигурации Web API:


config.Services.Replace(typeof(IActionValueBinder), new MyActionValueBinder());

Теперь в примере с массивом из начала статьи мы можем опустить явное назначение атрибута [FromUri]:


 public string Get(int[] ids)
 {
    return "Success: " + string.Concat(ids);
 }

Комментариев нет:

Отправить комментарий