在HttpStatusCode.Unauthorized之后使用Polly重试

时间:2017-01-28 13:00:39

标签: c# asp.net-mvc polly

我正在调用外部API并希望处理调用返回Unauthorized HttpResponseMessage的事件。发生这种情况时,我想刷新访问令牌并再次拨打电话。

我尝试使用以下代码Polly

    public async Task<HttpResponseMessage> MakeGetRequestAsync()
    {
        var retryPolicy = Policy
            .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
            .Retry(1, (exception, retryCount) =>
            {
                RefreshAccessToken();
            });

        var result = await retryPolicy.ExecuteAsync(() => CallApiAsync());

        return result;
    }


    private async Task<HttpResponseMessage> CallApiAsync()
    {
        var url = Options.ResourceSandboxUrl;

        var httpClient = new HttpClient();
        SetRequestHeaders(httpClient);
        var response = await httpClient.GetAsync(url);

        response.StatusCode = HttpStatusCode.Unauthorized;
        return response;
    }
  

我在ExecuteAsync语句和DoSomethingAsync中放置了断点 - 当我跳过ExecuteAsync DoSomethingAsync时未调用,并且控制权返回给调用MakeGetRequestAsync的函数1}}

我不明白为什么DoSomethingAsync没有被召唤 - 任何人都可以帮助我实现我想要实现的目标吗?

我看过Polly文档&amp;关于Stack Overflow的Polly问题,但我无法弄清楚发生了什么......

3 个答案:

答案 0 :(得分:6)

要使用ExecuteAsync(),您必须将政策声明为.RetryAsync(...),而不是.Retry(...)

如果您的实际代码与上面的代码示例完全相同,则.ExecuteAsync(...)会因.Retry(...) [同步策略]与.ExecuteAsync(...) [异步执行]之间的不匹配而失败。由于抛出此异常,因此确实从未调用CallApiAsync()。在调用MakeGetRequestAsync()

时,您应该能够看到抛出的异常

总体代码方法看起来很好:此重试 - 刷新 - 身份验证是proven pattern with Polly

答案 1 :(得分:2)

我要回答这个老问题只是为了指出正式记录了该模式的Polly Wiki页面:

retry-to-refresh-authorization

尤其是以下建议的代码段:

var authorisationEnsuringPolicy = Policy
    .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized) 
    .RetryAsync(
       retryCount: 1, // Consider how many retries. If auth lapses and you have valid credentials, one should be enough; too many tries can cause some auth systems to blacklist. 
       onRetryAsync: async (outcome, retryNumber, context) => FooRefreshAuthorizationAsync(context), 
      /* more configuration */); 

var response = authorisationEnsuringPolicy.ExecuteAsync(context => DoSomethingThatRequiresAuthorization(context), cancellationToken);

FooRefreshAuthorizationAsync(...)方法可以获得一个新的授权令牌,并将其传递给使用Polly.Context通过策略执行的委托。

答案 2 :(得分:1)

这就是异步等待在.net中工作的方式,当代码执行到this.时,会发生两件事

  1. 代码的当前线程应该释放以使您的代码异步,这意味着,您的方法应该返回

  2. 当你等待的任务完成后,你的方法应该从以前的地方继续