diff --git a/src/Libraries/Microsoft.Extensions.Http.Resilience/Resilience/ResilienceHttpClientBuilderExtensions.Resilience.cs b/src/Libraries/Microsoft.Extensions.Http.Resilience/Resilience/ResilienceHttpClientBuilderExtensions.Resilience.cs index 1829aefa101..48a565db41b 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Resilience/Resilience/ResilienceHttpClientBuilderExtensions.Resilience.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Resilience/Resilience/ResilienceHttpClientBuilderExtensions.Resilience.cs @@ -2,11 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.ExceptionSummarization; using Microsoft.Extensions.Http.Resilience; using Microsoft.Extensions.Http.Resilience.Internal; +using Microsoft.Shared.DiagnosticIds; using Microsoft.Shared.Diagnostics; using Polly; using Polly.Registry; @@ -75,6 +77,28 @@ public static IHttpResiliencePipelineBuilder AddResilienceHandler( return pipelineBuilder; } + /// + /// Removes all resilience handlers registered earlier. + /// + /// The builder instance. + /// The value of . + [Experimental(diagnosticId: DiagnosticIds.Experiments.Resilience, UrlFormat = DiagnosticIds.UrlFormat)] + public static IHttpClientBuilder RemoveAllResilienceHandlers(this IHttpClientBuilder builder) + { + _ = Throw.IfNull(builder); + _ = builder.ConfigureAdditionalHttpMessageHandlers(static (handlers, _) => + { + for (int i = handlers.Count - 1; i >= 0; i--) + { + if (handlers[i] is ResilienceHandler) + { + handlers.RemoveAt(i); + } + } + }); + return builder; + } + private static Func> CreatePipelineSelector(IServiceProvider serviceProvider, string pipelineName) { var resilienceProvider = serviceProvider.GetRequiredService>(); diff --git a/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Resilience/HttpClientBuilderExtensionsTests.Resilience.cs b/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Resilience/HttpClientBuilderExtensionsTests.Resilience.cs index 5ceb74f2217..54e0ab3f3e3 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Resilience/HttpClientBuilderExtensionsTests.Resilience.cs +++ b/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Resilience/HttpClientBuilderExtensionsTests.Resilience.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -286,6 +287,77 @@ public void AddResilienceHandler_AuthorityByCustomSelector_NotValidated() Assert.NotNull(factory.CreateClient("my-client")); } + [Fact] + public void RemoveAllResilienceHandlers_ArgumentValidation() + { + var services = new ServiceCollection(); + IHttpClientBuilder? builder = null; + Assert.Throws(() => builder!.RemoveAllResilienceHandlers()); + } + + [Fact] + public void RemoveAllResilienceHandlers_EnsureHandlersRemoved() + { + var services = new ServiceCollection(); + + IHttpClientBuilder? builder = services.AddHttpClient("custom"); + + builder.AddStandardResilienceHandler(); + + builder.ConfigureAdditionalHttpMessageHandlers((handlers, _) => + { + Assert.Single(handlers); + }); + + builder.RemoveAllResilienceHandlers(); + + builder.ConfigureAdditionalHttpMessageHandlers((handlers, _) => + { + Assert.Empty(handlers); + }); + + using ServiceProvider serviceProvider = services.BuildServiceProvider(); + serviceProvider.GetRequiredService().CreateClient("custom"); + } + + [Fact] + public void RemoveAllResilienceHandlers_AddHandlersAfterRemoval() + { + var services = new ServiceCollection(); + + IHttpClientBuilder? builder = services.AddHttpClient("custom"); + builder.RemoveAllResilienceHandlers().AddStandardResilienceHandler(); + builder.ConfigureAdditionalHttpMessageHandlers((handlers, _) => + { + Assert.Single(handlers); + }); + + using ServiceProvider serviceProvider = services.BuildServiceProvider(); + serviceProvider.GetRequiredService().CreateClient("custom"); + } + + [Fact] + public void RemoveAllResilienceHandlers_EnsureOnlyResilienceHandlersRemoved() + { + var services = new ServiceCollection(); + + IHttpClientBuilder? builder = services.AddHttpClient("custom"); + + builder.AddHttpMessageHandler(() => new TestHandlerStub(HttpStatusCode.OK)); + builder.AddStandardResilienceHandler(); + + builder.RemoveAllResilienceHandlers(); + + builder.ConfigureAdditionalHttpMessageHandlers((handlers, _) => + { + Assert.Single(handlers); + Assert.Equal(typeof(TestHandlerStub), handlers.First().GetType()); + }); + + using ServiceProvider serviceProvider = services.BuildServiceProvider(); + serviceProvider.GetRequiredService().CreateClient("custom"); + } + private void ConfigureBuilder(ResiliencePipelineBuilder builder) => builder.AddTimeout(TimeSpan.FromSeconds(1)); private class TestMetricsEnricher : MeteringEnricher