web-dev-qa-db-fra.com

Lire HttpContent dans le contrôleur Web Api

Comment puis-je lire le contenu de la demande PUT dans l'action du contrôleur MVC webApi.

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

Je reçois une chaîne vide ici :(

Ce que je dois faire est de savoir: "quelles propriétés" ont été modifiées/envoyées dans la requête initiale (ce qui signifie que si l'objet Contact a 10 propriétés et que je ne souhaite mettre à jour que 2 d'entre elles, j'envoie et 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"}
65
Marty

De par sa conception, le contenu du corps dans l’API Web ASP.NET est traité comme un flux avant uniquement pouvant être lu une seule fois.

La première lecture de votre cas est effectuée lorsque l'API Web lie votre modèle, après quoi la Request.Content ne retournera rien.

Vous pouvez supprimer le contact de vos paramètres d'action, obtenir 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 faire l'affaire (en supposant que accountId soit un paramètre d'URL, il ne sera donc pas traité comme du contenu lu).

124
tpeczek

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());
}

Renvoyé pour moi 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 ici

18
Anytoe

Même si cette solution peut sembler évidente, je voulais simplement la poster ici pour que le prochain gars la recherche plus rapidement sur Google.

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

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 ajoutez-le aux gestionnaires de messages globaux:

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

Cette solution est basée sur le réponse par Darrel Miller .

De cette façon, toutes les demandes seront mises en mémoire tampon.

4
derwasp