dotnet / dotnet/extensions

[API Proposal]: Resilience extensions - Expose StandardResiliencePipeline as a DelegatingHandler or ResiliencePipeline<HttpResponseMessage> in addition to the current AddStandardResilienceHandler extension method

Open
#6,164 0 comments 0 reactions 0 assignees View on GitHub
api-suggestion area-resilience untriaged
Dominant language
C#
Stars
3.2k
Forks
894
Avg merge
1d 12h
Merged PRs (30d)
23

Description

### Background and motivation

### Motivation

The standard resilience pipeline is a best practice, and we would like to adopt for most of our services. However, we notice that the only way to use the standard resilience pipeline directly is through the `IHttpClientBuilder` interface. This means that before a service could start to take benefits of the resilience extension library, it has to firstly refactor all its old HttpClient initialization pattern to the `HttpClientFactory` pattern. This is bad news for legacy services who simply new `HttpClient` directly from `DelegatingHandlers`.

By encapsulating the resilience logic of the standard resilience pipeline and exposing it as a `DelegatingHandler` directly or expose a ready to use `Func>` (which can be used to initialize a `ResilienceHandler` directly) for standard resilience pipeline, we enable services that rely on long-lived `HttpClient` instances to leverage .NET Resilience Extensions. This allows them to create standard resilience pipelines and use them as `DelegatingHandler`, just like services that adopt `HttpClientFactory`.

The same to other pipelines provided by .NET resilience extension library, like standard hedging, etc.

### API Proposal

In today's .NET resilience library, there is already a [AddHttpResiliencePipeline](https://source.dot.net/#Microsoft.Extensions.Http.Resilience/Resilience/[ResilienceHttpClientBuilderExtensions.Resilience.cs](https://source.dot.net/#Microsoft.Extensions.Http.Resilience/Resilience/ResilienceHttpClientBuilderExtensions.Resilience.cs,134),134) private method, who underlying uses the Polly's [IServiceCollection.AddResiliencePipeline](https://www.pollydocs.org/advanced/dependency-injection#usage) method.

We can add a similar API `IServiceCollection.AddStandardResiliencePipeline` in .NET resilience extension library.

```csharp
public static IHttpStandardResiliencePipelineBuilder AddStandardResiliencePipeline(this IServiceCollection services, string name)
{
var pipelineName = name;
var key = new HttpKey(pipelineName, string.Empty);
_ = services.AddResiliencePipeline(key, (builder, context) => {
var resilienceHandlerContext = new ResilienceHandlerContext(context);
builder.AddXXX
...
do the standard resilience logic
});

ConfigureHttpServices(services);
}
```

The main purpose of goal is to encapsulate the Standard Resilience logic inside and then make it easy to use not only from `IHttpClientBuilder`, but also for other cases.

### API Usage

```csharp
var services = new ServiceCollection();
services.AddStandardResiliencePipeline("standard-resilience-pipeline");
var serviceProvider = services.BuildServiceProvider();
ResilienceHandler standardResilienceHandler = CreateResilienceHandler(CreatePipelineProvider(serviceProvider, "standard-resilience-pipeline"))
var httpClient = new HttpClient(standardResilienceHandler);

private static Func> CreatePipelineProvider(IServiceProvider serviceProvider, string pipelineName)
{
_ = Throws.IfNull(serviceProvider);
_ = Throws.IfNullOrEmpty(pipelineName);

string pipelineName2 = pipelineName;
ResiliencePipelineProvider resilienceProvider = serviceProvider.GetRequiredService>();
ResiliencePipeline pipeline = resilienceProvider.GetPipeline(pipelineName2);
return (request) => pipeline;
}

private static ResilienceHandler CreateResilienceHandler(Func> pipelineProvider) =>
new ResilienceHandler(pipelineProvider);
```

### Alternative Designs

Another acceptable way is to instead of exposing the standard resilience pipeline as a Polly Resilience Pipeline, it's also ok to expose it as a ready to use `DelegatingHandler`.

### Risks

Since this is asking to add new features without having to change existing code, so should have less risks.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.