Parametri stringa di query facoltativi nell'API Web ASP.NET


212

Devo implementare il seguente metodo WebAPI:

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

Tutti i parametri della stringa di query possono essere nulli. Cioè, il chiamante può specificare da 0 a tutti e 5 i parametri.

In MVC4 beta ero solito fare quanto segue:

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 non si comporta più così. Se specifico meno di 5 parametri, risponde 404dicendo:

Non è stata trovata alcuna azione sui "Libri" del controller corrispondenti alla richiesta.

Qual è la firma del metodo corretta per farlo funzionare come una volta, senza dover specificare il parametro facoltativo nel routing URL?


metti in azione [httpget].
user960567

2
Se imposto tutti i parametri viene chiamato il metodo; inoltre inizia con Getquindi viene automaticamente associato al HTTP GETmetodo ...
frapontillo

Ecco come funziona il routing delle API web, asp.net/web-api/overview/web-api-routing-and-actions/…
user960567

4
Sì. So come funziona. Non riesco proprio a farlo funzionare in QUESTA circostanza particolare.
frapontillo,

Come è stato compilato? string?non è un tipo valido. Non è possibile dichiarare stringcome tipo nullable poiché è un tipo di riferimento.
Ekoostik Martedì

Risposte:


307

Questo problema è stato risolto nella versione normale di MVC4. Ora puoi fare:

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

e tutto funzionerà fuori dalla scatola.


Posso usare null qui come impostazione predefinita? Ad esempio: string author = null?
Boris Zinchenko,

2
Sì, nullè considerata un'espressione costante e quindi un valore predefinito valido .
JDawg,

Mi chiedo perché dobbiamo menzionare i valori predefiniti anche per i parametri opzionali, come detto qui . Qualsiasi tipo in C # ha sempre un valore predefinito, quindi il runtime di routing avrebbe potuto assumere il valore predefinito del tipo se non lo avesse ricevuto dall'URI. Qual è la ragione tecnica dietro questo ?. Sono sicuro che ciò abbia a che fare con il raccoglitore di modelli.
RBT

@RBT In modo che il percorso possa essere abbinato
James Westgate,

Stavo usando i parametri della data e se li avessi impostati su nullable non funzionava. Quindi devo impostarlo nullable e impostare null come valore predefinito e utilizzare di conseguenza la convalida lato server e restituire i messaggi di errore. Ha funzionato.
Atta H.

85

È possibile passare più parametri come singolo modello come suggerito da vijay. Questo funziona per GET quando si utilizza l'attributo del parametro FromUri. Questo dice a WebAPI di riempire il modello dai parametri della query.

Il risultato è un'azione del controller più pulita con un solo parametro. Per ulteriori informazioni, consultare: 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; }
  }

Supporta anche più parametri, purché le proprietà non siano in conflitto.

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

Aggiornamento :
per garantire che i valori siano opzionali, assicurarsi di utilizzare tipi di riferimento o nullable (es. Int?) Per le proprietà dei modelli.


4
Sì, ma il decoratore [FromUri] da solo non sembra supportare parametri opzionali.
John Meyer,

6
@JohnMeyer Hai ragione quando usi [FromUri] non risponde direttamente alla domanda originale. In pratica dice che popolare questi modelli con i valori di Uri. Le proprietà dei modelli dovrebbero essere nullable o un tipo di riferimento per poter essere opzionali. Aggiunte ulteriori informazioni.
Andrew C,

@AndrewC - Potresti approfondire quando / perché devi usare nullable per assicurarti che i valori siano opzionali? Se i valori non sono nulli (ad es. Proprietà int Skip) e non è stato specificato alcun parametro di query per quella proprietà, il metodo Controller API corrisponderà comunque correttamente alla richiesta e il valore per Skipsarà solo il valore predefinito per quel tipo, o 0 in questo caso
Clark

2
@Clark - Senza usare un tipo nullable non saprai se l'utente non ha fornito un valore e ha ottenuto il valore del tipo non inizializzato (0 per int) o se l'utente ha specificato 0. Usando nullable sei sicuro che l'utente lo abbia lasciato indefinito pertanto è possibile applicare in sicurezza l'impostazione predefinita nell'azione del controller. Se guardi Take dall'esempio sopra, cosa dovrebbe fare l'azione se ha ricevuto 0 per Take? L'utente intendeva richiedere 0 record o non lo ha specificato e quindi è necessario prendere tutti i record. In genere, se si desidera che un tipo di valore (int, bool, ecc.) Sia facoltativo, dovrebbe essere nullable.
Andrew C,

70

Utilizzare i valori predefiniti iniziali per tutti i parametri come di seguito

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

1
Questa è la procedura corretta ma per prima cosa: DateTimenon è nullable. Ho già provato a utilizzare DateTime?invece, ma MVC non associa la richiesta al metodo specificato se imposto solo alcuni dei parametri nella mia richiesta HTTP.
frapontillo,

puoi passare la data come stringa e analizzarla all'interno della tua funzione controller usando la funzione DateTime.Parse ().
Muhammad Amin,

1
@MuhammadAmin, DateTimenon è un tipo di dati nullable . Il codice non deve essere compilato, in quanto non sarebbe possibile assegnare un nullvalore a un parametro di tipo DateTime. Forse, dovresti cambiarlo DateTime?o usare un valore diverso per un like predefinito DateTime.Now.
Ivaylo Slavov il

1
@IvayloSlavov DateTime.Now non è una costante di tempo di compilazione, quindi non può essere assegnata come parametro predefinito.
GiriB,

@GiriB, hai davvero ragione. Datetime.Nownon può essere utilizzato nell'inizializzazione di parametri predefiniti, sono corretto.
Ivaylo Slavov,

1

se si desidera passare più parametri, è possibile creare un modello anziché passare più parametri.

nel caso in cui non si desideri passare alcun parametro, è possibile saltare anche in esso e il codice apparirà pulito e ordinato.


1
Questo è vero solo per i parametri POST nel corpo della richiesta: i parametri nell'URL possono ancora essere indicati individualmente come argomenti.
Nathan,

1

I valori predefiniti non possono essere forniti per parametri non dichiarati ' optional'

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

Nel tuo 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
In realtà, possono. Sto usando C #, non VB.NET.
Frapontillo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.