The library provides an outgoing request resiliency pipeline for HttpClient
, using policies from the PoliNorError library.
- Provides the ability to create a pipeline to handle typical transient HTTP failures (including the
HttpRequestException
exception). - Flexible transient failure filter for the final
DelegatingHandler
in the pipeline for the response. - Additionally, custom failure status codes or categories can be added to the final handler filter.
- Other exception types (besides
HttpRequestException
) can also be included in the final handler filter. - Inclusion in the outer handler filter of any
Exception
type thrown by the inner handler is also supported. - Both typed and named
HttpClient
, as well asIHttpClientFactory
, can be used. - Targets .NET Standard 2.0.
- ➡ OuterHandler is the first handler in the pipeline (closest to the request initiator).
- ⬅ InnerHandler is the next handler in the pipeline (closer to the final destination).
- 🔵 FinalHandler is the innermost handler in the pipeline.
- ❌ Transient HTTP errors are temporary failures that occur when making HTTP requests (HTTP 5xx, HTTP 408, HTTP 429 and
HttpRequestException
).
⚙ Configure typed or named HttpClient
:
services.AddHttpClient<IAskCatService, AskCatService>((sp, config) =>
{
...
config.BaseAddress = new Uri(settings.BaseUri);
...
})...
, where AskCatService
is a service that implements IAskCatService
, with HttpClient
or IHttpClientFactory
injected.
🧩 Use the library's IHttpClientBuilder.WithResiliencePipeline
extension method and configure the pipeline of DelegatingHandler
s by using the AddPolicyHandler
method with the policy you want to apply in this handler:
services.AddHttpClient<IAskCatService, AskCatService>((spForClient, client) =>
{
...
})
.WithResiliencePipeline((pb) =>
pb
.AddPolicyHandler(PolicyJustCreated)
.AddPolicyHandler((IServiceProvider sp) => funcThatUsesServiceProviderToCreatePolicy(sp))
...
)
Or use the WithResiliencePipeline
method overload that includes an additional context parameter:
services.AddHttpClient<IAskCatService, AskCatService>((spForClient, client) =>
{
...
})
.WithResiliencePipeline<SomeContextType>((pb) =>
pb
.AddPolicyHandler((SomeContextType ctx, IServiceProvider sp) =>
funcThatUsesContextAndServiceProviderToCreatePolicy(ctx, sp))
.AddPolicyHandler((IServiceProvider sp) => funcThatUsesServiceProviderToCreatePolicy(sp))
...
, context)
, where
pb
- represents the pipeline builder.PolicyJustCreated
- a policy from the PoliNorError library.funcThatUsesServiceProviderToCreatePolicy
-Func
that uses theIServiceProvider
to create a policy.funcThatUsesContextAndServiceProviderToCreatePolicy
-Func
that uses theIServiceProvider
and context to create a policy.
🔵 When you want to complete the pipeline, call the AsFinalHandler
method for the last added handler and configure HttpErrorFilter
to filter transient http errors and/or any non-successful status codes or categories:
services.AddHttpClient<IAskCatService, AskCatService>((sp, config) =>
{
...
})
.WithResiliencePipeline((pb) =>
pb
...
.AddPolicyHandler(PolicyForFinalHandler)
// ✔ Adds transient http errors to the response handling filter.
.AsFinalHandler(HttpErrorFilter.HandleTransientHttpErrors())
...
)
Additionally, you can include custom failure status codes or categories in the final handler filter:
...
.AsFinalHandler(HttpErrorFilter.HandleHttpRequestException()
// ✔ Also adds 5XX status codes to the response handling filter.
.OrServerError())
...
You can also include in the filter any exception type thrown by an inner handler:
...
.AsFinalHandler(HttpErrorFilter.HandleTransientHttpErrors())
// ✔ Include 'SomeExceptionFromNonPipelineHandler' exceptions in the filter
//when thrown by a non-pipeline handler (in this case).
.IncludeException<SomeExceptionFromNonPipelineHandler>()
...
⚾ In a service that uses HttpClient
or HttpClientFactory
, wrap the call to HttpClient
in a catch block that handles the special HttpPolicyResultException
exception.
If the request was not successful, examine the HttpPolicyResultException
properties in this handler for details of the response:
try
{
...
using var response = await _client.GetAsync(uri, token);
...
}
catch (OperationCanceledException oe)
{
...
}
catch (HttpPolicyResultException hpre)
{
// ✔ If the response status code matches the handling filter status code:
if (hpre.HasFailedResponse)
{
//For example, log a failed status code.
logger.LogError("Failed status code: {StatusCode}.", hpre.FailedResponseData.StatusCode);
}
}
catch (Exception ex)
{
...
}
Public properties of the HttpPolicyResultException
:
InnerException
- if the response status code matches the handling filter status code, it will be the special
FailedHttpResponseException
; - otherwise, an exception is thrown by a handler, either inside or outside the pipeline.
- if the response status code matches the handling filter status code, it will be the special
FailedResponseData
- not null if the status code part of the handling filter matches the response status code.HasFailedResponse
- true ifFailedResponseData
is not null.PolicyResult
- specifies thePolicyResult<HttpResponseMessage>
result that is produced by a policy that belongs to theDelegatingHandler
that throws this exception.InnermostPolicyResult
- specifies thePolicyResult<HttpResponseMessage>
result produced by a policy of the final handler or by a handler in the pipeline that throws its own exception.IsErrorExpected
- indicates whether the filter for the original exception was satisfied.IsCanceled
- indicates whether the execution was canceled.
See the /samples folder for concrete examples.
Steve Gordon. HttpClientFactory in ASP.NET Core 2.1 (Part 3) :
https://www.stevejgordon.co.uk/httpclientfactory-aspnetcore-outgoing-request-middleware-pipeline-delegatinghandlers
Martin Tomka. Building resilient cloud services with .NET 8 : https://devblogs.microsoft.com/dotnet/building-resilient-cloud-services-with-dotnet-8/
Thomas Levesque. Fun with the HttpClient pipeline : https://thomaslevesque.com/2016/12/08/fun-with-the-httpclient-pipeline/
Milan Jovanovic. Extending HttpClient With Delegating Handlers in ASP.NET Core :
https://www.milanjovanovic.tech/blog/extending-httpclient-with-delegating-handlers-in-aspnetcore
Josef Ottosson. Testing your Polly policies :
https://josef.codes/testing-your-polly-policies/