2012-11-05 25 views
30

Ho il seguente metodo Web API in una classe ApiController:ottenere i dati grezzi da POST metodo Web API

public HttpResponseMessage Post([FromBody]byte[] incomingData) 
{ 
    ... 
} 

voglio incomingData ad essere il contenuto grezzo del POST. Ma sembra che lo stack API Web tenta di analizzare i dati in arrivo con il formattatore JSON, e questo fa sì che il seguente codice sul lato client a fallire:

new WebClient().UploadData("http://localhost:15134/api/Foo", new byte[] { 1, 2, 3 }); 

C'è una soluzione semplice per questo?

risposta

39

Per chiunque altro in esecuzione in questo problema, la soluzione è quella di definire il metodo POST senza parametri, e accedere ai dati grezzi via Request.Content:

+3

avevo bisogno di qualcosa di simile, ma per le stringhe, e garantire che vi era alcun parametro nel metodo POST finito per essere essenziale per usando l'equivalente 'ReadAsStringAsync', era vuoto altrimenti. –

+0

Questo è il modo più semplice per farlo che ho trovato. I nostri partner continuano ad aggiungere nuovi campi non documentati che vogliono che usiamo e non sappiamo mai esattamente come vengono scritti/formattati. Grazie! – MvcCmsJon

+0

Grazie per questo. In MVC6 per ottenere tutto il corpo, ho dovuto rimuovere i parametri e leggere 'Request.Body' manualmente. – joe

3

In MVC 6 Richiesta non sembra avere un Proprietà 'Contenuto'. Ecco quello che ho finito per fare:

[HttpPost] 
public async Task<string> Post() 
{ 
    string content = await new StreamReader(Request.Body).ReadToEndAsync(); 
    return "SUCCESS"; 
} 
19

Se è necessario l'ingresso grezzo oltre al parametro del modello per facilitare l'accesso, è possibile utilizzare il seguente:

using (var contentStream = await this.Request.Content.ReadAsStreamAsync()) 
{ 
    contentStream.Seek(0, SeekOrigin.Begin); 
    using (var sr = new StreamReader(contentStream)) 
    { 
     string rawContent = sr.ReadToEnd(); 
     // use raw content here 
    } 
} 

Il segreto sta usando stream.Seek(0, SeekOrigin.Begin) per ripristinare lo stream prima di provare a leggere i dati.

+0

Grazie per questo, ho pubblicato una risposta in base al tuo codice, se vuoi incorporarlo sentiti libero e cancellerò la mia risposta. – Rocklan

10

Le altre risposte suggeriscono di rimuovere il parametro di input, ma questo interromperà tutto il codice esistente. Per rispondere alla domanda correttamente, una soluzione più semplice è quella di creare una funzione che assomiglia a questo (grazie a Christoph sotto di questo codice):

private async Task<String> getRawPostData() 
{ 
    using (var contentStream = await this.Request.Content.ReadAsStreamAsync()) 
    { 
     contentStream.Seek(0, SeekOrigin.Begin); 
     using (var sr = new StreamReader(contentStream)) 
     { 
      return sr.ReadToEnd(); 
     } 
    } 
} 

e quindi ottenere il grezzo ha registrato i dati all'interno della vostra chiamata API web in questo modo:

public HttpResponseMessage Post ([FromBody]byte[] incomingData) 
{ 
    string rawData = getRawPostData().Result; 

    // log it or whatever 

    return Request.CreateResponse(HttpStatusCode.OK); 
} 
+1

Bel lavoro, grazie! Sto aggiungendo una risposta che rigurgita la tua come una classe di utilità con un metodo statico. –

+3

lol, ora siamo a tre livelli di profondità. – Rocklan

+0

Se si accede all'attività .Result come quella, si esegue immediatamente un'attesa sul thread. C'è qualche vantaggio nell'usare un compito qui? – codinglifestyle

3

ho preso la risposta di LachlanB e metterlo in una classe di utilità con un metodo statico singolo che posso utilizzare in tutti i miei controllori.

public class RawContentReader 
{ 
    public static async Task<string> Read(HttpRequestMessage req) 
    { 
     using (var contentStream = await req.Content.ReadAsStreamAsync()) 
     { 
      contentStream.Seek(0, SeekOrigin.Begin); 
      using (var sr = new StreamReader(contentStream)) 
      { 
       return sr.ReadToEnd(); 
      } 
     } 
    } 
} 

Allora posso chiamare da uno qualsiasi dei metodi di mio ApiController in questo modo:

Problemi correlati