【问题标题】:Error when using HttpClient inside DelegatingHandler: The request message was already sent. Cannot send the same request message multiple times在 DelegatingHandler 中使用 HttpClient 时出错:请求消息已发送。无法多次发送相同的请求消息
【发布时间】:2017-04-24 19:40:00
【问题描述】:

在下面的代码 sn-p 中,我试图实现一个 DelegatingHandler。您会注意到,在 SendAsync 方法中,我偏离了将请求传递给 InnerHandler 的传统做法...

base.SendAsync(request, cancellationToken);

...而是创建一个新的 HttpClient 实例,我将请求传递给它:

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

这在像这样一个简单的 sn-p 中可能看起来很奇怪,但这里的想法是根据特定条件将请求传递给不同的 HttpClientHandler,所以我需要能够动态地实例化 HttpClient。

但是,当我运行此代码时,我收到以下异常:

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

有人可以帮助我了解导致它的原因以及实现我的要求的更好方法(在处理程序中克隆请求而不是传递它,这是可行的,但看起来并不优雅)?

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

    }
}

【问题讨论】:

  • 查看 HttpClient 的源代码,我现在看到异常来自哪里:github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/… 看起来我的代码导致请求通过 HttpClient 的两个实例:只要第一个看到它,它将它标记为已发送,当它到达第二个时,它已经损坏了货物。尽管如此,仍然需要帮助来寻找解决方法——简单地克隆请求似乎是一种处理问题的愚蠢方式。

标签: c# dotnet-httpclient system.net


【解决方案1】:

DelagatingHandler 需要一个内部处理程序才能运行,因此您似乎只需要确保在其中传递一个请求处理程序实例。

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

}

【讨论】:

  • 谢谢@andym1978,但是您发布的回复是调用基类的 SendAsync 方法的示例(这就是您需要在构造函数中定义内部处理程序的原因)。正如我在问题中提到的,我需要在我的 SendAsync 覆盖中创建一个新的 HttpClient 实例的灵活性,在这种情况下,永远不会调用内部处理程序。再次感谢您提供帮助。
【解决方案2】:

我可能误解了你的要求,但是如果你只需要在各种处理程序之间做出决定,你能不能在调用base.SendAsync()之前给InnerHandler分配合适的HttpClientHandler?像这样:

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

    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-14
    • 2021-11-17
    相关资源
    最近更新 更多