85 votes

Lire HttpContent dans le contrôleur WebApi

Comment lire le contenu d'une requête PUT dans une action de contrôleur webApi MVC.

[HttpPut]
public HttpResponseMessage Put(int accountId, Contact contact)
{
    var httpContent = Request.Content;
    var asyncContent = httpContent.ReadAsStringAsync().Result;
...

J'obtiens une chaîne vide ici :(

Ce que je dois faire, c'est déterminer "quelles propriétés" ont été modifiées/envoyées dans la demande initiale (c'est-à-dire que si le fichier Contact a 10 propriétés, et que je ne veux mettre à jour que 2 d'entre elles, j'envoie un objet avec seulement deux propriétés, quelque chose comme ceci :

{

    "FirstName": null,
    "LastName": null,
    "id": 21
}

Le résultat final attendu est

List<string> modified_properties = {"FirstName", "LastName"}

156voto

tpeczek Points 12722

De par sa conception, le contenu du corps de l'ASP.NET Web API est traité comme un flux transmissible qui ne peut être lu qu'une seule fois.

Dans votre cas, la première lecture est effectuée lorsque l'API Web lie votre modèle. Request.Content ne renvoie rien.

Vous pouvez retirer le contact à partir des paramètres de votre action, récupérer le contenu et le désérialiser manuellement en objet (par exemple avec Json.NET) :

[HttpPut]
public HttpResponseMessage Put(int accountId)
{
    HttpContent requestContent = Request.Content;
    string jsonContent = requestContent.ReadAsStringAsync().Result;
    CONTACT contact = JsonConvert.DeserializeObject<CONTACT>(jsonContent);
    ...
}

Cela devrait suffire (en supposant que accountId est un paramètre d'URL, il ne sera donc pas traité comme un contenu lu).

20voto

andytoe Points 63

Vous pouvez conserver votre paramètre CONTACT avec l'approche suivante :

using (var stream = new MemoryStream())
{
    var context = (HttpContextBase)Request.Properties["MS_HttpContext"];
    context.Request.InputStream.Seek(0, SeekOrigin.Begin);
    context.Request.InputStream.CopyTo(stream);
    string requestBody = Encoding.UTF8.GetString(stream.ToArray());
}

me renvoie la représentation json de mon objet paramètre, afin que je puisse l'utiliser pour la gestion des exceptions et la journalisation.

Trouvé comme réponse acceptée aquí

4voto

derwasp Points 607

Même si cette solution semble évidente, je tenais à la poster ici pour que le suivant la trouve plus rapidement sur Google.

Si vous souhaitez toujours que le modèle soit un paramètre de la méthode, vous pouvez créer un fichier DelegatingHandler pour mettre le contenu en mémoire tampon.

internal sealed class BufferizingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        await request.Content.LoadIntoBufferAsync();
        var result = await base.SendAsync(request, cancellationToken);
        return result;
    }
}

Et l'ajouter aux gestionnaires de messages globaux :

configuration.MessageHandlers.Add(new BufferizingHandler());

Cette solution est basée sur la répondre par Darrel Miller .

De cette manière, toutes les demandes seront mises en mémoire tampon.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X