Необязательные параметры строки запроса в ASP.NET Web API

212

Мне нужно реализовать следующий метод WebAPI:

/api/books?author=XXX&title=XXX&isbn=XXX&somethingelse=XXX&date=XXX

Все параметры строки запроса могут быть нулевыми. То есть вызывающая сторона может указать от 0 до всех 5 параметров.

В бета-версии MVC4 я делал следующее:

public class BooksController : ApiController
{
    // GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
    public string GetFindBooks(string author, string title, string isbn, string somethingelse, DateTime? date) 
    {
        // ...
    }
}

MVC4 RC больше не ведет себя так. Если я укажу менее 5 параметров, он отвечает 404поговоркой:

На контроллере «Книги» не найдено никаких действий, соответствующих запросу.

Какова правильная сигнатура метода, чтобы он вел себя так, как раньше, без необходимости указывать необязательный параметр в маршрутизации URL?

frapontillo
источник
положить [httpget] в действие.
user960567
2
Если я установлю все параметры, метод будет вызван; кроме того, он начинается с Getтого, что он автоматически связан с HTTP GETметодом ...
frapontillo
Это как веб - апи маршрутизации работы, asp.net/web-api/overview/web-api-routing-and-actions/...
user960567
4
Да. Я знаю, как это работает. Я просто не могу заставить его работать при ЭТОМ особом обстоятельстве.
фрапонтильо
Как это вообще скомпилировать? string?не является допустимым типом. Вы не можете объявить stringкак обнуляемый тип, так как это ссылочный тип.
EkoostikMartin

Ответы:

307

Эта проблема была исправлена ​​в обычном выпуске MVC4. Теперь вы можете сделать:

public string GetFindBooks(string author="", string title="", string isbn="", string  somethingelse="", DateTime? date= null) 
{
    // ...
}

и все будет работать из коробки.

frapontillo
источник
Могу ли я использовать ноль здесь по умолчанию? Например: строка author = null?
Борис Зинченко
2
Да, nullсчитается константным выражением и, следовательно, допустимым значением по умолчанию .
JDawg
Интересно, почему мы должны упоминать значения по умолчанию даже для необязательных параметров, как здесь сказано . Любой тип в C # всегда имеет значение по умолчанию, поэтому во время выполнения маршрутизации могло быть принято значение по умолчанию для типа, если он не получил его от URI. Какова техническая причина этого? Я уверен, что это как-то связано с моделью связующего.
RBT
@RBT, чтобы маршрут можно было
Джеймс Вестгейт,
Я использовал параметры даты, и если я просто установил их в nullable, не работал. Поэтому я должен установить его как nullable и установить null в качестве значения по умолчанию, и соответственно использовать проверку на стороне сервера и возвращать сообщения об ошибках обратно. Это сработало.
Atta H.
85

Можно передать несколько параметров как одну модель, как предложил Виджай. Это работает для GET, когда вы используете атрибут параметра FromUri. Это говорит WebAPI заполнить модель из параметров запроса.

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

public class BooksController : ApiController
  {
    // GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
    public string GetFindBooks([FromUri]BookQuery query)
    {
      // ...
    }
  }

  public class BookQuery
  {
    public string Author { get; set; }
    public string Title { get; set; }
    public string ISBN { get; set; }
    public string SomethingElse { get; set; }
    public DateTime? Date { get; set; }
  }

Он даже поддерживает несколько параметров, если свойства не конфликтуют.

// GET /api/books?author=tolk&title=lord&isbn=91&somethingelse=ABC&date=1970-01-01
public string GetFindBooks([FromUri]BookQuery query, [FromUri]Paging paging)
{
  // ...
}

public class Paging
{
  public string Sort { get; set; }
  public int Skip { get; set; }
  public int Take { get; set; }
}

Обновление :
чтобы гарантировать, что значения являются необязательными, обязательно используйте ссылочные типы или обнуляемые значения (например, int?) Для свойств моделей.

Андрей С
источник
4
Да, но один декоратор [FromUri] не поддерживает дополнительные параметры.
Джон Мейер
6
@JohnMeyer Вы правильно используете [FromUri], не отвечает прямо на оригинальный вопрос. Это в основном говорит, что заполняют эти модели значениями из Uri. Свойства моделей должны быть обнуляемыми или ссылочными, чтобы они могли быть необязательными. Добавлена ​​дополнительная информация.
Андрей C
@AndrewC - Не могли бы вы уточнить, когда и почему вам нужно использовать обнуляемые значения, чтобы значения были необязательными? Если вы не сделаете значения обнуляемыми (например, свойство int Skip), и для этого свойства не задан параметр запроса, метод API Controller все равно будет успешно соответствовать запросу, а значение для Skipбудет просто значением по умолчанию для этого типа, или 0 в этом случае
Кларк
2
@Clark - Без использования типа NULL вы не будете знать, не предоставил ли пользователь значение и получил ли значение неинициализированного типа (0 для int) или если пользователь указал 0. Используя NULL, вы уверены, что пользователь оставил его неопределенным поэтому вы можете смело применять настройки по умолчанию в действии контроллера. Если вы посмотрите на Take из приведенного выше примера, что должно делать действие, если оно получило 0 для Take? Пользователь хотел запросить 0 записей или они не указали его, и поэтому вы должны взять все записи. Обычно, если вы хотите, чтобы тип значения (int, bool и т. Д.) Был необязательным, он должен иметь значение null.
Андрей C
70

Используйте начальные значения по умолчанию для всех параметров, как показано ниже

public string GetFindBooks(string author="", string title="", string isbn="", string  somethingelse="", DateTime? date= null) 
{
    // ...
}
Мухаммед Амин
источник
1
Это правильная процедура, но с одной стороны: DateTimeне обнуляется. Я уже пытался использовать DateTime?вместо этого, но тогда MVC не отображает запрос на данный метод, если я установил только некоторые параметры в моем HTTP-запросе.
фрапонтильо
Вы можете передать дату в виде строки и проанализировать ее внутри функции контроллера, используя функцию DateTime.Parse ().
Мухаммед Амин
1
@MuhammadAmin, DateTimeэто не обнуляемый тип данных. Ваш код не должен компилироваться, так как вы не сможете присвоить nullзначение параметру типа DateTime. Возможно, вы должны изменить его DateTime?или использовать другое значение для значения по умолчанию DateTime.Now.
Ивайло Славов
1
@IvayloSlavov DateTime.Now не является постоянной времени компиляции, поэтому ее нельзя назначить параметром по умолчанию.
GiriB
@GiriB, ты действительно прав. Datetime.Nowне может использоваться при инициализации параметров по умолчанию, я исправлен.
Ивайло Славов
1

если вы хотите передать несколько параметров, вы можете создать модель вместо передачи нескольких параметров.

в случае, если вы не хотите передавать какой-либо параметр, вы также можете пропустить его, и ваш код будет выглядеть аккуратно и чисто.

Виджей
источник
1
Это верно только для параметров POST в теле запроса - параметры в URL могут по-прежнему ссылаться индивидуально в качестве аргументов.
Натан
1

Значения по умолчанию не могут быть предоставлены для параметров, которые не объявлены ' optional'

 Function GetFindBooks(id As Integer, ByVal pid As Integer, Optional sort As String = "DESC", Optional limit As Integer = 99)

В твоем WebApiConfig

 config.Routes.MapHttpRoute( _
          name:="books", _
          routeTemplate:="api/{controller}/{action}/{id}/{pid}/{sort}/{limit}", _
          defaults:=New With {.id = RouteParameter.Optional, .pid = RouteParameter.Optional, .sort = UrlParameter.Optional, .limit = UrlParameter.Optional} _
      )
Ризван Мумтаз
источник
8
На самом деле, они могут. Я использую C #, а не VB.NET.
Фрапонтильо