This is about policies and contexts using the Polly library (v7.2.3) and Microsoft.Extensions.Http.Polly (v7.0.5). I'm confused about the SetPolicyExecutionContext method of the HttpRequestMessage class: I know it works when policies are added to the HttpClient via an HttpClientFactory, but I'm using it in a case where the HttpClient does not have any policies attached and it's not working as I was expecting. The context is to be used later in the policy OnRetry delegate, like so:
OnRetry = (_, _, _, context) => {
var value = context.ContainsKey("X") ? (string)context["X"] : "NOT FOUND";
Debug.WriteLine(value);
},
The HttpRequest is sent using the ExecuteAsync method of the policy (after setting the context):
//Case 1 (Context in Request)
var context = new Context();
context.Add("X", "ABC");
request.SetPolicyExecutionContext(context);
policy.ExecuteAsync(() => _httpClient.SendAsync(request));
When this code executes and the web request fails, the OnRetry handler always writes "NOT FOUND" to the output.
But if the context is passed directly to the policy, like this:
//Case 2 (Context in Policy)
var context = new Context();
context.Add("myKey", "ABC");
policy.ExecuteAsync((token) => _httpClient.SendAsync(request), context);
Then it works as expected: on failed requests the output gets "ABC".
Why is that? I thought that in Case 1 the ExecuteAsync method would get the context from the request and pass it to the executing policy so it would be equivalent to Case 2, but that's not happening, so it looks like I'm missing something.
The
SetPolicyExecutionContextsimply does the following:which means after this call you can access the
contextvia theHttpRequestMessage'sPropertiescollection or simply by calling therequest.GetPolicyExecutionContext().So, it attaches a context to the request object NOT to the execution.
If you want to access the context inside the
OnRetry{Async}delegate then you have to explicitly pass thecontextto theExecute{Async}call.UPDATE #1: A bit more details
Whenever you use the
AddHttpClientwith theAddPolicyHandlerthen the context propagation is done on your behalf via thePolicyHttpMessageHandler. This class is aDelegatingHandlerand itsSendAsyncmethod does the magic for you:ExecuteAsyncSendAsynccall then it will delete the temporarily attached contextBased on your question I assume that you are not using the
PolicyHttpMessageHandlerso, no one will automatically pass the context to theExecuteAsync.