【问题标题】:Error 'The request message was already sent. Cannot send the same request message multiple times'错误'请求消息已发送。无法多次发送相同的请求消息'
【发布时间】:2021-09-01 17:10:25
【问题描述】:

这就是我正在尝试的:

public static async Task<HttpResponseMessage> post(string specificUrl, string token, StringContent inputData) // specificUrl like "user/" at the end "/"
{
    var policy = Policy
        .Handle<Exception>()
        .OrResult<HttpResponseMessage>(res => !res.IsSuccessStatusCode)
        .RetryAsync(3);

    string fullUrl = baseUrl + specificUrl;
    using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, fullUrl))
    {
        requestMessage.Content = inputData;
        requestMessage.Headers.Add("access_token", token);
        //HttpResponseMessage res = await client.SendAsync(requestMessage).ConfigureAwait(false);
        HttpResponseMessage res = await policy.ExecuteAsync(() => client.SendAsync(requestMessage)).ConfigureAwait(false);
        return res;
    }
}

只要代码达到 waitAndRetryPolicy 并等待所需的时间,我就会收到以下错误:

System.InvalidOperationException: '请求消息已经发送。不能多次发送相同的请求消息。

【问题讨论】:

    标签: c#


    【解决方案1】:

    简而言之,您不能重用HttpRequestMessage,它会处理在SendAsync 级别无法缓解的一大堆问题(例如流式内容等)。您需要在ExecuteAsync lambda 中创建/重新创建您的HttpRequestMessage,或者更好的是,使用IHttpClientFactory,然后在HttpClientBuilder 级别使用Polly

    重新创建HttpRequestMessage的示例

    return await policy.ExecuteAsync(() =>
    {
       // note the using here is a superfluous, but good practice
       using var requestMessage = new HttpRequestMessage(HttpMethod.Post, fullUrl) 
       {
           Content = new StringContent(aString) 
       };
    
       requestMessage.Headers.Add("access_token", token);
       return client.SendAsync(requestMessage);
    
    }).ConfigureAwait(false);
    

    但理想情况下,您应该将 HttpClientFactory 与类型化或命名的客户端一起使用

    给定一个类型化的客户端

    public class MyTypedClient
    {
       private readonly HttpClient _client;
    
       public MyTypedClient(HttpClient client) => _client = client;
       public async Task<HttpResponseMessage> MyCall(string inputData)
       {
          using var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/someRoute") { Content = new StringContent(inputData) };
          var result = await _client.SendAsync(requestMessage);
          result.EnsureSuccessStatusCode();
          return result;
       }
    }
    

    Di 用法示例

    private static readonly AsyncRetryPolicy<HttpResponseMessage> retryPolicy
       = HttpPolicyExtensions
          .HandleTransientHttpError() // what ever ??
          .RetryAsync(3);
    
    public static void Main()
    {
    
       var serviceCollection = new ServiceCollection();
    
       serviceCollection
          .AddHttpClient<MyTypedClient>(ClientConfiguration)
          .AddPolicyHandler(retryPolicy);
    
       var provider = serviceCollection.BuildServiceProvider();
       // what ever
    }
    
    private static void ClientConfiguration(HttpClient client)
    {
       client.BaseAddress = new Uri("http://bob.com");
       /// blah blah blah
    }
    

    注意:这并不是关于 Di、Polly 或其他任何东西的教程,例如世界最佳实践,如何在 AddHttpClient 级别使用身份验证等等,这只是一个使用策略如何组合在一起的示例用例

    Nuget

    • Microsoft.Extensions.DependencyInjection
    • Microsoft.Extensions.Http
    • Microsoft.Extensions.Http.Polly
    • 波莉

    其他资源

    【讨论】:

    • 感谢它提供了很多信息,第一个return await policy.ExecuteAsync(() =&gt;{} 触发错误':无法访问已处置的对象:'System.Net.Http.StringContent'。'。
    • @ShowMore 啊是我的错误,最好每次都创建内容(在这种情况下),这个问题还有更多,但是我想给你一个例子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    • 2023-03-24
    • 2017-08-18
    相关资源
    最近更新 更多