C# 在Polly重试策略中重用HttpRequestMessage

C# 在Polly重试策略中重用HttpRequestMessage,c#,dotnet-httpclient,polly,C#,Dotnet Httpclient,Polly,HttpRequestMessage对象只能使用一次;以后尝试使用同一对象时会引发异常。我正在使用Polly重试一些请求,我遇到了这个问题。我知道如何克隆请求,有很多这样的例子,但我不知道如何克隆请求并在Polly重试时发送新请求。我怎样才能做到这一点 这些是我的政策,供参考。这是一个Xamarin应用程序。如果出现网络故障,我想重试几次,如果响应未经授权,我想使用保存的凭据重新验证,然后重试原始请求 public static PolicyWrap<HttpResponseMessage

HttpRequestMessage
对象只能使用一次;以后尝试使用同一对象时会引发异常。我正在使用Polly重试一些请求,我遇到了这个问题。我知道如何克隆请求,有很多这样的例子,但我不知道如何克隆请求并在Polly重试时发送新请求。我怎样才能做到这一点

这些是我的政策,供参考。这是一个Xamarin应用程序。如果出现网络故障,我想重试几次,如果响应未经授权,我想使用保存的凭据重新验证,然后重试原始请求

public static PolicyWrap<HttpResponseMessage> RetryPolicy
{
    get => WaitAndRetryPolicy.WrapAsync(ReAuthPolicy);
}

private static IAsyncPolicy WaitAndRetryPolicy
{
    get => Policy.Handle<WebException>().WaitAndRetryAsync(4, _ => TimeSpan.FromSeconds(2));
}

private static IAsyncPolicy<HttpResponseMessage> ReAuthPolicy
{
    get => Policy.HandleResult<HttpResponseMessage>(x => x.StatusCode == HttpStatusCode.Unauthorized)
        .RetryAsync((_, __) => CoreService.LogInWithSavedCredsAsync(true));
}

如果重用了
HttpRequestMessage
,则引发
InvalidOperationException
的代码是
HttpClient
本身的验证步骤

    private static void CheckRequestMessage(HttpRequestMessage request)
    {
        if (!request.MarkAsSent())
        {
            throw new InvalidOperationException(SR.net_http_client_request_already_sent);
        }
    }


您可以将polly重试策略放在
DelegatingHandler
中,这样就可以了。它还提供了一个很好的SoC(关注点分离)。如果将来不想重试或更改重试行为,只需删除
DelegatingHandler
或更改它即可。注意:要处理掉
HttpRequestMessage
和中间
HttpResponseMessage
s对象,请参见。将重试放在DelegatingHandler中可以避免无法重用的问题。如果ASPNET核心和U可以等到2.1 RTM,考虑新的。如果是这样的话,你也可以看看。@Mountaintraveler谢谢,不知怎么的,我还没见过那个。我不知道如何将它与我已有的政策结合起来,但是我很难理解波利政策应该如何协同工作。(这是一个Xamarin应用程序,尽管我认为这个问题已经足够普遍了,所以我没有包括在内。)IHttpClientFactory上的Polly doco讨论。这包括在不使用IHttpClientFactory的情况下使用DelegatingHandler方法应用多个策略。有关该概念的讨论,请参阅。如果在ASPNET Core 2.1之前,您必须手动创建DelegatingHandler链。如果您的查询通常是关于组合Polly策略时的行为,请参阅“是”,DelegatingHandler是HttpClient的中间件。没有一种方法可以将executeAndCaptureAync()与之结合,也就是说,在DelegatingHandler中。executeAndCaptureAync()更改执行的返回类型;但中间件不能做到这一点。
    private static void CheckRequestMessage(HttpRequestMessage request)
    {
        if (!request.MarkAsSent())
        {
            throw new InvalidOperationException(SR.net_http_client_request_already_sent);
        }
    }
    internal bool MarkAsSent()
    {
        return Interlocked.Exchange(ref sendStatus, messageAlreadySent) == messageNotYetSent;
    }