这是关于使用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相关问答推荐

.NET框架4.7.2项目如何引用.NET Core 2.2库?

需要澄清C#的Clean Architecture解决方案模板的AuditableEntityInterceptor类

实体框架核心上是否支持使用NPGSQL的字符串聚合?

try 在Blazor项目中生成html

Int和uint相乘得到LONG?

C#XmlSerializer-输出控制新行的多个XML片段

如何将ASP.NET Core 2.1(在.NET框架上运行)更新到较新的版本?

在实体框架中处理通用实体&S变更跟踪器

Cosmos SDK和Newtonsoft对静态只读记录的可能Mutations

C#中Java算法的类似功能

用于管理System.Text.Json中的多态反序列化的自定义TypeInfoResolver

TagHelpers在新区域不起作用

RX操作员使用先前值进行扫描,信号来自值本身

ASP.NET MVC数据批注验证组复选框

错误:此版本的Visual Studio无法打开以下项目

VS代码扩展无法在新版本扩展C#中运行从v2.10.28开始

如何使用.NET 8.0中新的CompositeFormat类?

在C#中删除多个不同名称的会话

Roslyn编译器看不到引用

组件';EditForm';使用与包含子内容元素';授权';相同的参数名称(';上下文';)