Необов'язкові параметри рядка запиту у веб-API ASP.NET


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?


покласти [httpget] на дію.
user960567

2
Якщо я встановив усі параметри, метод викликається; Крім того, він починається з, Getтому він автоматично пов'язаний з HTTP GETметодом ...
frapontillo

Так працює веб-маршрутизація api, asp.net/web-api/overview/web-api-routing-and-action/…
user960567

4
Так. Я знаю, як це працює. Я просто не можу змусити його працювати при ЦІЙ конкретній обставині.
frapontillo

Як це навіть складено? string?не є допустимим типом. Ви не можете оголосити stringнульовим типом, оскільки це еталонний тип.
EkoostikMartin

Відповіді:


307

Ця проблема була виправлена ​​в регулярному випуску MVC4. Тепер ви можете зробити:

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

і все вийде з коробки.


Чи можу я використовувати тут null як за замовчуванням? Наприклад: string author = null?
Борис Зінченко


Цікаво, чому ми маємо згадати значення за замовчуванням навіть для необов'язкових параметрів, про що тут говорилося . Будь-який тип у C # завжди має значення за замовчуванням, тому час виконання маршруту може прийняти значення типового типу, якби він не отримав його з URI. У чому полягає технічна причина цього? Я впевнений, що це має відношення до в'яжучої моделі.
RBT

@RBT Так що маршрут можна узгоджувати
Джеймс Вестгейт,

Я використовував параметри дати, і якщо я просто встановив їх на нульовий, не працює. Отже, я повинен встановити його нульовим і встановити null як значення за замовчуванням, і використовувати перевірку на стороні сервера відповідно і повернути повідомлення про помилки назад. Це спрацювало.
Атта Х.

85

Можна передавати кілька параметрів як одну модель, як запропонував vijay. Це працює для 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] безпосередньо не відповідає на початкове запитання. Це, по суті, говорить, заповнюйте ці моделі значеннями з Урі. Властивості моделей повинні бути нульовими або еталонними, щоб підтримувати їх необов'язково. Додана додаткова інформація.
Ендрю С

@AndrewC - Чи можете ви детальніше розказати, коли / чому вам потрібно використовувати нульові знаки, щоб переконатися, що значення необов’язкові? Якщо ви не зробите значення нульовими (для ex, властивості int Skip) і для вказаного властивості не вказано параметр запиту, метод контролера API все одно буде успішно відповідати запиту, а значення для Skipбуде просто значенням за замовчуванням для цього типу, або 0 у цьому випадку
Кларк

2
@Clark - Без використання зведеного типу ви не дізнаєтесь, чи користувач не вказав значення та отримав значення неініціалізованого типу (0 для int) або якщо користувач вказав 0. За допомогою nullable ви впевнені, що користувач залишив його невизначеним тому ви можете безпечно застосувати за замовчуванням дію контролера. Якщо ви подивитесь на Take з наведеного вище прикладу, що слід зробити, якщо вона отримала 0 для Take? Чи мав на увазі користувач запитувати 0 записів чи не вказав їх, і тому ви повинні взяти всі записи. Як правило, якщо ви хочете, щоб тип значення (int, bool і т. Д.) Був необов’язковим, він повинен бути зведений нанівець.
Ендрю С

70

Використовуйте початкові значення за замовчуванням для всіх параметрів, як показано нижче

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

1
Це правильна процедура, але з одного боку: DateTimeне зводиться до нуля. Я вже намагався використовувати DateTime?замість цього, але тоді MVC не відображає запит на даний метод, якщо я встановив лише деякі параметри у своєму запиті HTTP.
frapontillo

ви можете передавати дату як рядок і аналізувати її всередині функції контролера за допомогою функції 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.
frapontillo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.