Come devo passare più parametri a un ASP.Net Web API GET?


136

Sto usando l'API Web .Net MVC4 per (si spera) implementare un API RESTful. Devo passare alcuni parametri al sistema e farlo eseguire alcune azioni, quindi restituire un elenco di oggetti come risultati. In particolare, sto passando in due date e restituendo i record che cadono tra di loro. Sto anche tenendo traccia dei record restituiti in modo che le chiamate successive non vengano rielaborate nel sistema.

Ho preso in considerazione alcuni approcci:

  1. Serializzare i parametri in un'unica stringa JSON e selezionarli nell'API. http://forums.asp.net/t/1807316.aspx/1

  2. Passa i parametri nella stringa di query.
    Qual è il modo migliore per passare più parametri di query a un API riposante?

  3. Definizione dei parametri nel percorso: api / controller / date1 / date2

  4. Utilizzo di un POST che intrinsecamente mi consente di passare un oggetto con parametri.

  5. Ricerca ODATA poiché l'API Web (attualmente) la supporta. Non ho ancora fatto molto con questo, quindi non ne ho molta familiarità.

Sembra che le pratiche REST appropriate indicano quando i dati vengono estratti, è necessario utilizzare un GET. Tuttavia, GET dovrebbe anche essere nullipotent (non produce effetti collaterali) e mi chiedo se la mia implementazione specifica violi dal momento che segnare i record nel sistema API, quindi sto producendo effetti collaterali.

Mi ha anche portato alla questione del supporto di parametri variabili. Se l'elenco dei parametri di input cambia, sarebbe noioso dover ridefinire il percorso per Choice 3 se ciò accade molto. E cosa potrebbe accadere se i parametri fossero definiti in fase di esecuzione ...

In ogni caso, per la mia specifica implementazione, quale scelta (se presente) sembra la migliore?

Risposte:


10

Cosa significa questo segno di registrazione? Se questo viene utilizzato solo a fini di registrazione, utilizzare GET e disabilitare tutta la memorizzazione nella cache, poiché si desidera registrare ogni query per queste risorse. Se la marcatura dei record ha un altro scopo, POST è la strada da percorrere. L'utente dovrebbe sapere che le sue azioni incidono sul sistema e sul metodo POST è un avvertimento.


Contrassegnando intendo semplicemente tenere traccia dei record elaborati e restituiti in modo che le chiamate successive non li ripetano. Nel mio caso sto solo facendo un inserto in un'altra tabella per tracciare quali sono elaborati.
sig606,

In questo momento l'ho implementato come un POST principalmente per il motivo che hai detto: le azioni accadono e il consumatore ne è consapevole. Inoltre, sembra facile e molto flessibile rispetto al passaggio di dati diversi.
sig606

@ sig606: POST è la strada da percorrere per me, ma il tuo protocollo non sembra essere sicuro. Cosa succede se succede qualcosa e i record vengono recuperati sul lato client, ma non elaborati a causa di un bug? Non li restituirai più e il client rimarrà con i dati persi.
LukLed

Al momento la mia API restituisce i record solo dopo che sono stati elaborati. Quindi il consumatore passa l'API due date. I record tra queste due date vengono elaborati e contrassegnati. Quindi i dati vengono restituiti al chiamante. Suppongo che se si verifica qualcosa durante l'elaborazione o dopo l'elaborazione prima di raggiungere il client, ho un problema.
sig606,

141

Penso che il modo più semplice sia semplicemente usare AttributeRouting.

È ovvio nel tuo controller, perché dovresti volerlo nel tuo WebApiConfigfile Global ?

Esempio:

    [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

I {}nomi devono corrispondere ai tuoi parametri.

Semplice come quello, ora hai un separato GETche gestisce più parametri in questa istanza.


12
Questo è fantastico Molte persone consigliano di impostare il percorso nel WebApiConfigfile, ma questo è davvero più bello.
rhyek,

4
In effetti, noi (la maggior parte delle persone) raccomandiamo di avere un'area di gestione centralizzata per la tua configurazione. Nel caso di API Web (Microsoft o altro), i modelli centralizzati per REST sono fondamentali. Il routing degli attributi è carino, ma rende le eccezioni una tantum troppo allettanti.
David Betz,

3
D'accordo, devo aggiornare effettivamente la mia risposta. Esiste un modo molto migliore di eseguire più parametri con GET. Inserito questo quando ero nuovo in WebAPI, ora non uso AttributeRouting (a meno che non voglia semplicemente creare un nuovo controller) e passi tutti i parametri in QueryString, mappano automaticamente. Aggiornamento quando ne ho la possibilità, quindi le persone non usano questo vecchio metodo
Mark Pieszak - Trilon.io

C'è un modo per impostare un Routeper i parametri con nome (ad es. Parametri di query)?
Shimmy Weitzhandler,

1
Se è richiesto il nome del metodo di azione, questo può essere modificato per adattarlo. [Route ("api / YOURCONTROLLER / Get / {paramOne} / {paramTwo}")] stringa pubblica Get (int paramOne, int paramTwo) {return "qualcosa"; }
Dash

49

Aggiungi un nuovo percorso alle WebApiConfigvoci.

Ad esempio, per chiamare:

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

Inserisci:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

Quindi aggiungere i parametri alla chiamata HTTP:

GET //<service address>/Api/Data/2/10 

10
Questa sembra essere l'unica risposta che elenca tutte le parti. Vorrei che qualcuno descrivesse meglio come usare l' api/controller?start=date1&end=date2URI di stile.
Hot Licks

@Hot Licks La risposta di Andrew Veriga funziona bene con gli argomenti della stringa di query. In sostanza, si associano i nomi delle stringhe di query alle proprietà della classe e li si passa al proprio metodo. Il metodo prenderà un argomento di singola classe contrassegnato con l'attributo [FromUri] e avrà gli argomenti della stringa di query come proprietà.
David Peterson,

Roba fantastica. Grazie!
Hugo Nava Kopp,

ciao @HotLicks e GrahamWright pensi di poter rispondere a questa domanda? Grazie, stackoverflow.com/questions/57565318/...

45

Ho dovuto implementare un API RESTfull dove ho bisogno di passare i parametri. L'ho fatto passando i parametri nella stringa di query nello stesso stile descritto dal primo esempio di Mark "api / controller? Start = date1 & end = date2"

Nel controller ho usato un suggerimento da URL diviso in C #?

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

Nel mio caso stavo chiamando il WebApi via Ajax come:

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

Spero che aiuti...


2
Immagino che tu non stia usando WebApi perché ParameterBinding associerà automaticamente la tua querystring ai parametri del tuo metodo api ...
emp

1
Sì, un modo migliore sarebbe quello di usare e attribuire come [Route ("api / DbMetaData / {system} / {searchString}")] e quindi aggiungere lì parametri a Get (sistema di stringhe, stringSearchString) e quindi chiamare con " ... api / DbMetaData / mysystem / mysearchstring "
Nigel Findlater

Ho usato il suo esempio nel mio C # MVC WebApi e ha funzionato bene. +1 per esempio
Si8

38

Ho trovato un'ottima soluzione su http://habrahabr.ru/post/164945/

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

5
L'indizio qui è il [FromUri]
tranceporter il

2
Sebbene l'articolo sia in russo, @tranceporter ha ragione. "FromUri" sembra un ottimo modo per ottenere i parametri dall'URL. Un altro articolo che potrebbe essere utile: asp.net/web-api/overview/formats-and-model-binding/…
Greg

Questo è quello che faccio da un po 'di tempo ormai e ha funzionato alla grande! Consiglierei anche questa soluzione.
David Peterson,

Se si chiama in un altro metodo di supporto (non il Get), è ancora possibile utilizzare [FromUri]? Non riesco a farlo funzionare.
Giovedì

8

L'uso di GET o POST è chiaramente spiegato da @LukLed . Per quanto riguarda il modo in cui è possibile passare i parametri, suggerirei di seguire il secondo approccio (non so molto su ODATA ).

1.Serializzare i parametri in una singola stringa JSON e selezionarli nell'API. http://forums.asp.net/t/1807316.aspx/1

Questo non è facile da usare e SEO friendly

2.Inserire i parametri nella stringa della query. Qual è il modo migliore per passare più parametri di query a un API riposante?

Questo è il solito approccio preferibile.

3.Definizione dei parametri nel percorso: api / controller / date1 / date2

Questo non è sicuramente un buon approccio. Questo fa sentire che qualcuno date2è una sotto-risorsa date1e non è così. Sia l' date1e date2sono parametri di query e arriva allo stesso livello.

In casi semplici suggerirei un URI come questo,

api/controller?start=date1&end=date2

Ma personalmente mi piace il modello URI di seguito, ma in questo caso dobbiamo scrivere un codice personalizzato per mappare i parametri.

api/controller/date1,date2

In realtà, quelle erano le mie spiegazioni orig. Penso che LukLed abbia brillato i miei tag e il collegamento URL.
sig606,

Per quanto riguarda la SEO, in questo caso non si applica. Questo codice sarà "server-to-server", quindi non mi importerebbe se il mondo esterno lo scoprisse mai. In effetti, devo assicurarmi che vengano prese le opportune misure di sicurezza per evitare l'accesso casuale. Ho dovuto eseguire la serializzazione JSON per un'altra parte del sistema (sembra essere un bug che prova a POSTare grandi elenchi di oggetti, quindi ho dovuto serializzare su stringa), quindi in questo caso non sarebbe molto lungo .
sig606,

1
Spero che tu abbia già delle risposte, allora perché stai facendo domande?
VJAI

2
Ci scusiamo per questa risposta tardiva, Mark. Avevo provato alcune soluzioni ma non ero sicuro di quale fosse il migliore e stavo cercando di seguire gli approcci standard del settore, quindi ho pubblicato qui su SO.
sig606,

1
@Mark Qualcosa di simile al prossimo: stackoverflow.com/questions/9681658/… ?
RredCat


3
 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

Entrambi i parametri del collegamento radice ({one}, {two}) e i parametri della funzione Get (uno, due) devono essere uguali


2

So che è davvero vecchio, ma di recente ho voluto la stessa cosa ed ecco cosa ho trovato ...

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" && test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }

Quindi ora nel tuo indirizzo / URI / ...

http (s): // myURL / api / myController / var = getnew & Test = test

Risultato: "test trovato"


http (s): // myURL / api / myController / var = getnew & test = nulla

Risultato: "Impossibile trovare quel test"


Personalmente mi piace questo stile in C #, perché posso cambiare la firma del metodo originale e sovraccaricare esattamente ciò che sto cercando di realizzare, senza modificare le configurazioni di routing. Spero che aiuti gli altri che sono abituati a questo approccio (forse antiquato) di fare una richiesta GET.
Rick Riggs,

1
Ho dovuto creare un'API di eventi utilizzata da un'app di calendario di terze parti, che utilizza questo approccio. Sono contento di aver trovato questa risposta!
clayRay


0
    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        using (MarketEntities entities = new MarketEntities())
        {
          var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id && e.IDNO.ToString()== numb);
            if (ent != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, ent);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
            }
        }
    }
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.