2017-04-24 10 views
0

Dans l'extrait de code ci-dessous, j'essaie d'implémenter un DelegatingHandler. Vous remarquerez que dans la méthode SendAsync je déviant de la pratique conventionnelle de transmettre la demande au InnerHandler ...Erreur lors de l'utilisation de HttpClient dans DelegatingHandler: Le message de demande a déjà été envoyé. Impossible d'envoyer le même message de demande plusieurs fois

base.SendAsync(request, cancellationToken); 

... et au lieu am créer une nouvelle instance de HttpClient, à laquelle je passe la demande:

new HttpClient().SendAsync(request, cancellationToken); 

cela peut sembler étrange dans un extrait de l'os nu comme celui-ci, mais l'idée ici est de transmettre la demande à différents HttpClientHandlers selon certaines conditions, je vais donc besoin de pouvoir instancier HttpClient dynamiquement.

Cependant, quand je lance ce code, je reçois l'exception suivante:

The request message was already sent. Cannot send the same request message multiple times. 

Quelqu'un peut-il s'il vous plaît me aider à comprendre quelles sont les causes et ce serait une meilleure façon de mettre en œuvre mon exigence (court de cloner la requête dans le gestionnaire plutôt que de la transmettre, ce qui fonctionne, mais ne semble pas élégant)?

using System; 
using System.Net.Http; 
using System.Threading; 
using System.Threading.Tasks; 

namespace DelegatingHandlerTest 
{ 
    internal static class Program 
    { 
     private static void Main() 
     { 
      var httpClient = new HttpClient(new MyTestHandler()); 

      var response = httpClient.GetAsync("http://icanhazip.com/").Result; 

      Console.WriteLine(response.Content.ReadAsStringAsync().Result); 
     } 

    private class MyTestHandler : DelegatingHandler 
    { 

     protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
     { 
      return await new HttpClient().SendAsync(request, cancellationToken); 
     } 

    } 
} 
+0

En regardant le code source de HttpClient, je vois maintenant où l'exception provient de: https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/ src/System/Net/Http/HttpClient.cs # L599 On dirait que mon code fait passer la requête à travers deux instances de HttpClient: dès que le premier le voit, il le marque comme envoyé, et au moment où il arrive à la deuxième, il est déjà endommagé les biens. Vous avez toujours besoin d'aide pour trouver une solution de contournement - le simple clonage de la requête vous semble une manière stupide de gérer le problème. –

Répondre

0

Le DelagatingHandler a besoin d'un gestionnaire interne à la fonction, il semble que vous avez juste besoin de vous assurer que vous passez une instance de gestionnaire de requêtes là-dedans.

private static void Main() 
{ 
     var httpClient = new HttpClient(new MyTestHandler(new HttpClientHandler())); 

     var response = httpClient.GetAsync("http://icanhazip.com/").Result; 

     Console.WriteLine(response.Content.ReadAsStringAsync().Result); 
} 


private class MyTestHandler : DelegatingHandler 
{ 

     public MyTestHandler(HttpClientHandler handler) { 
      base.InnerHandler = handler; 
     } 

     protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
     { 
      return await base.SendAsync(request, cancellationToken); 
     } 

} 
+0

Merci @ andym1978, mais la réponse que vous avez envoyée est un exemple d'appel de la méthode SendAsync de la classe de base (c'est pourquoi vous devez définir un gestionnaire interne dans le constructeur). Comme je l'ai mentionné dans la question, j'ai besoin de la flexibilité de créer une nouvelle instance de HttpClient dans mon override SendAsync, et dans ce cas le gestionnaire interne ne serait jamais invoqué. Merci encore d'avoir essayé d'aider. –

0

je méprendre à vos besoins, mais si vous avez seulement besoin de choisir entre différents gestionnaires, pouvez-vous pas affecter la HttpClientHandler appropriée au InnerHandler avant d'appeler base.SendAsync()? Comme ceci:

private class MyTestHandler : DelegatingHandler 
{ 

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 

     if (someCondition) 
     { 
      base.InnerHandler = new MyHttpClientHandler(...); 
     } 

     else 
     { 
      base.InnerHandler = new MyOtherHttpClientHandler(...); 
     } 

     return await base.SendAsync(request, cancellationToken); 

    } 

} 
+0

Très pas thread thread ... – Tratcher