in the old version of Polly, I used this function to get a policy based on the request URI:
private static IAsyncPolicy<HttpResponseMessage> PolicySelector(IReadOnlyPolicyRegistry<string> policyRegistry,
HttpRequestMessage httpRequestMessage)
{
Guard.Against.Null(httpRequestMessage);
Guard.Against.Null(httpRequestMessage.RequestUri);
if (httpRequestMessage.RequestUri.AbsoluteUri.Contains(_consentsSettings.GetConsentsRequestUri))
{
return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>(Constants.PollyPipelineKey.GetConsents);
}
if (httpRequestMessage.RequestUri.AbsoluteUri.Contains(_consentsSettings.SetConsentsRequestUri))
{
return Policy.NoOpAsync<HttpResponseMessage>();
}
throw new InvalidOperationException("Polly policy for consents not found");
}
and on my HttpClient, I called this with the following code:
services.AddHttpClient(ConsentsService.ConsentsClientName, client =>
{
client.BaseAddress = new Uri(settings.BaseUri);
})
.AddPolicyHandlerFromRegistry(PolicySelector);
Now, I would like to use the new Polly.Core package. I have this code:
services.AddHttpClient(ConsentsService.ConsentsClientName, client =>
{
client.BaseAddress = new Uri(settings.BaseUri);
})
.AddResilienceHandler(Constants.PollyPipelineKey.GetConsents, (builder, context) =>
{
var factory = context.ServiceProvider.GetRequiredService<IHttpPollyPipelineFactory>();
var pipeline = factory.CreateResiliencePipeline();
builder.AddPipeline(pipeline);
})
But I don't know if it is possible to apply this resilience handler only when calling a specific URI, or if the only solution is to check the URI before the client call to PostAsync and wrap it with the pipeline's ExecuteAsync method.I hope I was clear. Thanks
At the time of writing, there is no AddResilienceHandler
overload which allows you to access the HttpRequestMessage
. So, currently you can't do the exact same branching during the pipeline registration like what you did in case of Polly V7.
BUT, there are two things worth mentioning.
SelectPipelineByAuthority
There is an extension method called SelectPipelineByAuthority
. This method caches and assigns pipeline for each authority (schema + protocol + port). This feature was designed mainly for circuit breakers but can be used elsewhere as well.
Here we have documented how to use it.
You could register multiple named clients. One which is decorated with your resilience pipeline the other without it.
Here the key thing is to find meaningful and expressive names to ease the selection of the proper client for given use cases.
UPDATE #1
There is a workaround. Since 8.2.0 the Microsoft.Extensions.Http.Resilience
package exposes the ResilienceHandler
class, which was internal
before this release.
This class has a ctor which allows you to access the request and define which pipeline you want to use. With that you can do something like this:
services
.AddHttpClient(ConsentsService.ConsentsClientName, client => { ... })
.AddHttpMessageHandler(sp => new ResilienceHandler(req => YourPipelineSelector(sp, req)));
The NoOp
equivalent for V8 is the ResiliencePipeline.Empty
.