这是关于使用Polly库(v7.2.3)和Microsoft.Extensions.Http.Polly(v7.0.5)的策略和上下文.我对HttpRequestMessage类的SetPolicyExecutionContext方法感到困惑:我知道当通过HttpClientFactory将策略添加到HttpClient时,它可以工作,但我在HttpClient没有附加任何策略并且它不像我预期的那样工作的情况下使用它.该上下文将在稍后的策略重试委托中使用,如下所示:

OnRetry = (_, _, _, context) => {
    var value = context.ContainsKey("X") ? (string)context["X"] : "NOT FOUND";
    Debug.WriteLine(value); 
},

使用策略的ExecuteAsync方法发送HttpRequest(在设置上下文之后):

//Case 1 (Context in Request)
var context = new Context();
context.Add("X", "ABC");
request.SetPolicyExecutionContext(context);
policy.ExecuteAsync(() => _httpClient.SendAsync(request));

当此代码执行且Web请求失败时,OnReter处理程序始终将"未找到"写入输出.

但是如果上下文直接传递给策略,就像这样:

//Case 2 (Context in Policy)
var context = new Context();
context.Add("myKey", "ABC");
policy.ExecuteAsync((token) => _httpClient.SendAsync(request), context);

然后它就像预期的那样工作:在失败的请求中,输出为"ABC".

为什么会这样呢?我以为在 case 1中,ExecuteAsync方法将从请求中获取上下文并将其传递给执行策略,因此它将等同于 case 2,但这并没有发生,所以看起来我遗漏了一些东西.

推荐答案

SetPolicyExecutionContext只做了following:

request.Properties["PolicyExecutionContext"] = pollyContext;

这意味着在此呼叫之后,您可以通过HttpRequestMessageProperties集合或简单地通过呼叫request.GetPolicyExecutionContext()来访问context.

因此,它将上下文附加到请求对象,而不是附加到执行.

如果你想访问OnRetry{Async}委托内部的上下文,那么你必须显式地将context传递给Execute{Async}调用.


UPDATE #1:更多细节

每当您将AddHttpClientAddPolicyHandler一起使用时,就会通过PolicyHttpMessageHandler代表您完成上下文传播.这个类是一个DelegatingHandler,它的SendAsync方法为您变魔术:

var cleanUpContext = false;
var context = request.GetPolicyExecutionContext();
if (context == null)
{
    context = new Context();
    request.SetPolicyExecutionContext(context);
    cleanUpContext = true;
}

HttpResponseMessage response;
try
{
    var policy = _policy ?? SelectPolicy(request);
    response = await policy.ExecuteAsync((c, ct) => SendCoreAsync(request, c, ct), context, cancellationToken).ConfigureAwait(false);
}
finally
{
    if (cleanUpContext)
    {
        request.SetPolicyExecutionContext(null);
    }
}

return response;
  1. 它try 从请求中检索上下文
  2. 如果它不存在,则将创建一个新的temporarily
  3. 它将上下文显式传递给ExecuteAsync
  4. 如果在呼叫SendAsync时没有附加到请求的上下文,则它将删除附加的temporarily上下文

根据您的问题,我假设您没有使用PolicyHttpMessageHandler,因此,没有人会自动将上下文传递给ExecuteAsync.

Csharp相关问答推荐

如何将两个查询结果组合在C#ASP.NET MHC控制器中

Regex在c#中完全匹配

EF Core判断是否应用了AsSplitQuery()

解析需要HttpClient和字符串的服务

在具有不同属性名称的两个类之间创建关系

为什么无法将对象转换为泛型类型

CS1660无法将lambda表达式转换为类型INavigationBase,因为它不是委托类型

如何使用MoQ模拟Resources GroupCollection?

取决于您的数据量的多个嵌套循环

使用带有参数和曲面的注入失败(&Q;)

Swagger没有显示int?可以为空

Linux Docker上的.NET6在某个时间抛出后,在加密操作期间发生System.Security.Cryptography.CryptographicException:错误

自定义列表按字符串的部分排序

将内置的OrderedEumable&Quot;类设置为内部类有什么好处?

如何避免在.NET中将日志(log)写入相对路径

类/值和日期的泛型方法

如何使用实体框架核心对字符串_agg使用强制转换为varchar(Max)

为什么在使用JsonDerivedType序列化泛型时缺少$type?

当我在Git中暂存文件更改时,它们会消失

是否在异步方法中避免Span<;T>;.ToArray()?