HttpContent.ReadAsStringAsync provoque demande à accrocher (ou d'autres comportements étranges)

Nous construisons un très simultanées de l'application web, et nous avons récemment commencé à utiliser de la programmation asynchrone en profondeur (à l'aide de TPL et async/await).

Nous avons un environnement distribué, dans les applications qui communiquent les uns avec les autres via des Api REST (construite sur le toit de ASP.NET l'API Web). Dans une application particulière, nous avons un DelegatingHandler qu'après l'appel de base.SendAsync (c'est à dire, après le calcul de la réponse) les journaux de la réponse à un fichier. Nous incluons la réponse des informations de base dans le journal (code d'état, les en-têtes et le contenu):

public static string SerializeResponse(HttpResponseMessage response)
{
    var builder = new StringBuilder();
    var content = ReadContentAsString(response.Content);

    builder.AppendFormat("HTTP/{0} {1:d} {1}", response.Version.ToString(2), response.StatusCode);
    builder.AppendLine();
    builder.Append(response.Headers);

    if (!string.IsNullOrWhiteSpace(content))
    {
        builder.Append(response.Content.Headers);

        builder.AppendLine();
        builder.AppendLine(Beautified(content));
    }

    return builder.ToString();
}

private static string ReadContentAsString(HttpContent content)
{
    return content == null ? null : content.ReadAsStringAsync().Result;
}

Le problème, c'est que lorsque le code atteint content.ReadAsStringAsync().Result sous une lourde charge sur le serveur, la demande se bloque parfois sur IIS. Quand il le fait, il retourne parfois une réponse -- mais se bloque sur IIS comme si elle n'avait pas-ou en d'autres temps, il ne revient jamais.

J'ai aussi essayé de lire le contenu à l'aide de ReadAsByteArrayAsync et de le convertir ensuite à String, avec pas de chance.

Quand je convertir le code à utiliser asynchrone à travers je suis de plus en plus étrange résultats:

public static async Task<string> SerializeResponseAsync(HttpResponseMessage response)
{
    var builder = new StringBuilder();
    var content = await ReadContentAsStringAsync(response.Content);

    builder.AppendFormat("HTTP/{0} {1:d} {1}", response.Version.ToString(2), response.StatusCode);
    builder.AppendLine();
    builder.Append(response.Headers);

    if (!string.IsNullOrWhiteSpace(content))
    {
        builder.Append(response.Content.Headers);

        builder.AppendLine();
        builder.AppendLine(Beautified(content));
    }

    return builder.ToString();
}

private static Task<string> ReadContentAsStringAsync(HttpContent content)
{
    return content == null ? Task.FromResult<string>(null) : content.ReadAsStringAsync();
}

Maintenant HttpContext.Current est null après l'appel à content.ReadAsStringAsync(), et , il continue à être nulle pour toutes les demandes subséquentes! Je sais que cela semble incroyable-et il m'a fallu du temps et de la présence de trois collègues à accepter que ce qui se passe réellement.

Ce n'est pas le comportement attendu? Suis-je en train de faire quelque chose de mal ici?

Vous vous rendez compte que l'appel ReadContentAsStringAsync, puis immédiatement à l'appel de Result sur, fondamentalement, c'est la négation de l'asynchronie, droit? Qui permet de bloquer jusqu'à ce que le travail est terminé. Et HttpContext.Current être null après l'attendent sonne comme il n'est tout simplement pas s'écoulant à travers await points, ce qui est ennuyeux, mais n'a pas entièrement surprise pour moi. Vous pourrait chercher à la démarrer de votre méthode async et ensuite utiliser cette variable locale...
Je serais probablement appel envelopper un try catch autour d'un appel à la réaction.EnsureSuccessStatusCode() avant même de tenter de traiter le contenu.
Êtes-vous sûr qu'il est toujours possible de lire HttpResponseMessage.Content? Il me semble que d'essayer de lire vos propres flux de sortie ne peuvent pas être pris en charge.
oui je suis conscient de cela. La seule raison pour laquelle j'ai "bloqué" l'opération a été d'essayer d'éviter de perdre HttpContext.Current "forever" qui, je l'ai fait, mais ensuite il y a la pendaison de problème. En passant, je ne pense pas que vous avez bien compris, mais HttpContext.Current n'est pas perdu jusqu'à la fin de la Requête HTTP. Il est perdu pour la suite des Requêtes HTTP. Je ne peux obtenir de retour avec un iisreset.
qu'entendez-vous par là? Aussi loin que je suis concerné, je ne suis pas l'écriture d'un flux directement à response.Content, je suis en utilisant ObjectContent à la place.

OriginalL'auteur alextercete | 2013-07-22