web-dev-qa-db-fra.com

Impossible de lire Request.Content dans le contrôleur WebApi ASP.NET

J'écris un proxy utilisant WebApi dans un exe TransferMode.Streamed HttpSelfHostConfiguration.

Lorsque j'utilise fiddler pour publier sur ApiController, pour une raison quelconque, je ne peux pas lire le Request.Content - il renvoie "" même si j'ai des données POST

public class ApiProxyController : ApiController
{

    public Task<HttpResponseMessage> Post(string path)
    {
        return Request.Content.ReadAsStringAsync().ContinueWith(s =>
        {
            var content = new StringContent(s.Result); //s.Result is ""
                CopyHeaders(Request.Content.Headers, content.Headers);
            return Proxy(path, content);
        }).Unwrap();
    }

    private Task<HttpResponseMessage> Proxy(string path, HttpContent content)
    {
        ...
    }
}

Voici ma demande web 

POST http://localhost:3001/api/values HTTP/1.1
Host: localhost:3001
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Type: application/json
Content-Length: 26

{ "text":"dfsadfsadfsadf"}

Qu'est ce que je fais mal? Pourquoi le résultat revient-il sous forme de chaîne vide plutôt que de json brut?

23
mcintyre321

J'ai finalement réussi à faire fonctionner cela en héritant de l'interface de base au lieu d'ApiController - je pense que l'ApiController était modelbinding, ce qui dévorait la réponse.

edit: La bonne chose pour construire un proxy est un MessageHandler, pas un ApiController

4
mcintyre321

Moi aussi j'ai eu du mal avec ça. ReadAsStringAsync et ReadAsAsync retournent un objet de tâche. Référencer la propriété Result renvoie le contenu. Il se peut que la référence à la propriété Result provoque le blocage de la demande de lecture async.

Exemple:

string str = response.Content.ReadAsStringAsync().Result;
35
JeffR

Je sais que c'est vieux et qu'on y a répondu, mais pour ce que cela vaut, la raison pour laquelle vous ne pouvez pas utiliser ReadAsStringAsync() n'est pas parce qu'il "mange les données" comme cela a été suggéré, c'est parce que le contenu est traité en tant que flux et puisque les données ont été consommées par le formateur de message, la position du flux est déjà à la fin.

Pour utiliser ReadAsStringAsync(), vous devez d’abord réinitialiser la position du flux de contenu au début.

Je le fais comme ceci: response.RequestMessage.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin ) car je ne dispose que de HttpResponseMessage, mais si vous avez un accès direct à HttpRequestMessage (comme vous le faites dans le contrôleur), vous pouvez utiliser Request.Content.ReadAsStreamAsync().Result.Seek( 0, System.IO.SeekOrigin.Begin ) qui est fonctionnellement équivalent, je suppose.

18
Richard Hauer

Cette signature pour post mange les données de post:

public HttpResponseMessage Post([FromBody]string postdata)

changez le en:

public HttpResponseMessage Post()

alors cet appel fonctionne bien pour obtenir les données de poste:

string str = response.Content.ReadAsStringAsync().Result;

Testé moi-même. utilisez la première signature, str est vide, utilisez la deuxième str a poster data!

16
JJ_Coder4Hire

Je pense que vous avez raison quand ApiController mange le Request.Content. L'objet "Request" que vous voyez dans ApiController est en fait de type System.Net.Http.HttpRequestMessage. J'ai pu contourner ce problème mais en sauvegardant l'objet System.Web.HttpRequest comme suit:

Dim content as string
If HttpContext.Current.Request.InputStream.CanSeek Then
    HttpContext.Current.Request.InputStream.Seek(0, IO.SeekOrigin.Begin)
End If
Using reader As New System.IO.StreamReader(HttpContext.Current.Request.InputStream)
    content = reader.ReadToEnd()
End Using

Je ne sais pas si le retour en arrière est nécessaire mais je le mets juste au cas où.

5
EverPresent
  1. Request.Content.ReadAsStreamAsync (). Result.Seek (0, System.IO.SeekOrigin.Begin)
  2. new System.IO.StreamReader (Request.Content.ReadAsStreamAsync (). Résultat) .ReadToEnd ()
2
HGMamaci

Vous devez utiliser un type complexe pour votre argument puis utiliser dans le corps un json comme

{chemin: "c: ..."}

Les als utilisent le 

Type de contenu: application/json; jeu de caractères = UTF-8 

en-tête dans votre demande de publication afin que l'API Web sache que JSON est contenu dans le corps

0
Gertjan

Essayez de remplacer ReadAsStringAsync() par ReadAsAsync<string>().

0
David Peden