/// <summary>
        /// Adds a <see cref="PolicyHttpMessageHandler"/> which will surround request execution with the provided
        /// <see cref="IAsyncPolicy{HttpResponseMessage}"/>.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="policy">The <see cref="IAsyncPolicy{HttpResponseMessage}"/>.</param>
        /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
        /// <remarks>
        /// <para>
        /// See the remarks on <see cref="PolicyHttpMessageHandler"/> for guidance on configuring policies.
        /// </para>
        /// </remarks>
        public static IHttpClientBuilder AddPolicyHandler(this IHttpClientBuilder builder, IAsyncPolicy <HttpResponseMessage> policy)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (policy == null)
            {
                throw new ArgumentNullException(nameof(policy));
            }

            builder.AddHttpMessageHandler(() => new PolicyHttpMessageHandler(policy));
            return(builder);
        }
        /// <summary>
        /// Adds a <see cref="PolicyHttpMessageHandler"/> which will surround request execution with a <see cref="Policy"/>
        /// created by executing the provided configuration delegate. The policy builder will be preconfigured to trigger
        /// application of the policy for requests that fail with a connection or server error (5XX status code).
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="configurePolicy">A delegate used to create a <see cref="IAsyncPolicy{HttpResponseMessage}"/>.</param>
        /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
        /// <remarks>
        /// <para>
        /// See the remarks on <see cref="PolicyHttpMessageHandler"/> for guidance on configuring policies.
        /// </para>
        /// <para>
        /// The <see cref="PolicyBuilder{HttpResponseMessage}"/> provided to <paramref name="configurePolicy"/> has been
        /// preconfigured to handle connection errors (as <see cref="HttpRequestException"/>) or server errors (as a 5XX HTTP
        /// status code). The configuration is similar to the following code sample:
        /// <code>
        /// Policy.HandleAsync&lt;HttpRequestException&gt;().OrResult&lt;HttpResponseMessage&gt;(response =>
        /// {
        ///     return response.StatusCode >= HttpStatusCode.InternalServerError;
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// The policy created by <paramref name="configurePolicy"/> will be cached indefinitely per named client. Policies
        /// are generally designed to act as singletons, and can be shared when appropriate. To share a policy across multiple
        /// named clients, first create the policy and the pass it to multiple calls to
        /// <see cref="AddPolicyHandler(IHttpClientBuilder, IAsyncPolicy)"/> or
        /// <see cref="AddPolicyHandler(IHttpClientBuilder, IAsyncPolicy{HttpResponseMessage})"/> as desired.
        /// </para>
        /// </remarks>
        public static IHttpClientBuilder AddServerErrorPolicyHandler(
            this IHttpClientBuilder builder,
            Func <PolicyBuilder <HttpResponseMessage>, IAsyncPolicy <HttpResponseMessage> > configurePolicy)
        {
            var policyBuilder = Policy.Handle <HttpRequestException>().OrResult <HttpResponseMessage>(response =>
            {
                return(response.StatusCode >= HttpStatusCode.InternalServerError);
            });

            // Important - cache policy instances so that they are singletons per handler.
            var policy = configurePolicy(policyBuilder);

            builder.AddHttpMessageHandler(() => new PolicyHttpMessageHandler(policy));
            return(builder);
        }
예제 #3
0
        public static IHttpClientBuilder AddAuthentication(this IHttpClientBuilder builder,
                                                           Func <IServiceProvider, ClientCredentials> credentialsProvider,
                                                           Func <IServiceProvider, string> identityAuthorityProvider)
        {
            builder.Services.TryAddSingleton <AccessTokensCacheManager>();
            builder.AddHttpMessageHandler(provider =>
            {
                var credentials       = credentialsProvider.Invoke(provider);
                var identityAuthority = identityAuthorityProvider.Invoke(provider);

                return(CreateDelegatingHandler(provider, credentials, identityAuthority));
            });

            return(builder);
        }
        /// <summary>
        /// Adds the retry handler.
        /// </summary>
        /// <param name="builder">The builder.</param>
        /// <param name="retryPolicyOptions">The retry policy options.</param>
        /// <returns>IHttpClientBuilder.</returns>
        /// <exception cref="System.ArgumentNullException">builder</exception>
        /// <exception cref="System.ArgumentNullException">retryPolicyOptions</exception>
        public static IHttpClientBuilder AddRetryHandler(this IHttpClientBuilder builder, HttpRetryPolicyOptions retryPolicyOptions)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (retryPolicyOptions == null)
            {
                throw new ArgumentNullException(nameof(retryPolicyOptions));
            }

            builder.AddHttpMessageHandler(() => new RetryDelegatingHandler(retryPolicyOptions));

            return(builder);
        }
 public static IHttpClientBuilder AddNaosMessageHandlers(this IHttpClientBuilder builder, Action <IHttpClientBuilder> setupAction = null)
 {
     if (setupAction != null)
     {
         setupAction.Invoke(builder);
         return(builder);
     }
     else
     {
         // default handlers
         return(builder
                .AddHttpMessageHandler <HttpClientCorrelationHandler>()
                .AddHttpMessageHandler <HttpClientServiceContextHandler>()
                .AddHttpMessageHandler <HttpClientLogHandler>());
     }
 }
예제 #6
0
        /// <summary>
        /// Adds <see cref="HttpRecorderDelegatingHandler"/> as a HttpMessageHandler in the client pipeline.
        /// </summary>
        /// <param name="httpClientBuilder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="interactionName">
        /// The name of the interaction.
        /// If you use the default <see cref="IInteractionRepository"/>, this will be the path to the HAR file (relative or absolute) and
        /// if no file extension is provided, .har will be used.
        /// </param>
        /// <param name="mode">The <see cref="HttpRecorderMode" />. Defaults to <see cref="HttpRecorderMode.Auto" />.</param>
        /// <param name="matcher">
        /// The <see cref="IRequestMatcher"/> to use to match interactions with incoming <see cref="HttpRequestMessage"/>.
        /// Defaults to matching Once by <see cref="HttpMethod"/> and <see cref="HttpRequestMessage.RequestUri"/>.
        /// <see cref="RulesMatcher.ByHttpMethod"/> and <see cref="RulesMatcher.ByRequestUri"/>.
        /// </param>
        /// <param name="repository">
        /// The <see cref="IInteractionRepository"/> to use to read/write the interaction.
        /// Defaults to <see cref="HttpArchiveInteractionRepository"/>.
        /// </param>
        /// <param name="anonymizer">
        /// The <see cref="IInteractionAnonymizer"/> to use to anonymize the interaction.
        /// Defaults to <see cref="RulesInteractionAnonymizer.Default"/>.
        /// </param>
        /// <returns>The updated <see cref="IHttpClientBuilder"/>.</returns>
        public static IHttpClientBuilder AddHttpRecorder(
            this IHttpClientBuilder httpClientBuilder,
            string interactionName,
            HttpRecorderMode mode             = HttpRecorderMode.Auto,
            IRequestMatcher matcher           = null,
            IInteractionRepository repository = null,
            IInteractionAnonymizer anonymizer = null)
        {
            var recorder = new HttpRecorderDelegatingHandler(
                interactionName,
                mode: mode,
                matcher: matcher,
                repository: repository,
                anonymizer: anonymizer);

            return(httpClientBuilder.AddHttpMessageHandler((sp) => recorder));
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="clientBuilder"></param>
        /// <param name="accessMethod"></param>
        /// <param name="tokenEndpoint"></param>
        /// <param name="clientId"></param>
        /// <param name="clientSecret"></param>
        /// <param name="tokenStore"></param>
        /// <returns></returns>
        public static void AddOAuth(
            this IHttpClientBuilder clientBuilder,
            string accessMethod,
            string tokenEndpoint,
            string clientId,
            string clientSecret,
            ITokenStore tokenStore)
        {
            if (string.IsNullOrEmpty(accessMethod))
            {
                throw new ArgumentNullException(nameof(accessMethod));
            }
            if (string.IsNullOrEmpty(tokenEndpoint))
            {
                throw new ArgumentNullException(nameof(tokenEndpoint));
            }
            if (string.IsNullOrEmpty(clientId))
            {
                throw new ArgumentNullException(nameof(clientId));
            }
            if (string.IsNullOrEmpty(clientSecret))
            {
                throw new ArgumentNullException(nameof(clientSecret));
            }

            if (tokenStore == null)
            {
                throw new ArgumentNullException(nameof(tokenStore));
            }

            clientBuilder.Services.AddScoped(_ => tokenStore);
            clientBuilder.Services.AddScoped(s =>
            {
                var client = new TokenClient(
                    tokenEndpoint,
                    clientId,
                    clientSecret);
                return(new IdentityModelTokenClientAdapter(client));
            });
            clientBuilder.Services.AddScoped(s =>
            {
                var tokenManager = s.GetRequiredService <ITokenNegotiator>();
                return(new AccessTokenDelegatingHandler(tokenManager));
            });
            clientBuilder.AddHttpMessageHandler <AccessTokenDelegatingHandler>();
        }
예제 #8
0
        /// <summary>
        /// 添加token应用的http消息处理程序
        /// </summary>
        /// <typeparam name="TOAuthTokenHandler"></typeparam>
        /// <param name="builder"></param>
        /// <param name="handlerFactory">hanlder的创建委托</param>
        /// <param name="tokenProviderSearchMode">token提供者的查找模式</param>
        /// <returns></returns>
        public static IHttpClientBuilder AddOAuthTokenHandler <TOAuthTokenHandler>(this IHttpClientBuilder builder, Func <IServiceProvider, ITokenProvider, TOAuthTokenHandler> handlerFactory, TypeMatchMode tokenProviderSearchMode = TypeMatchMode.TypeOrBaseTypes)
            where TOAuthTokenHandler : OAuthTokenHandler
        {
            var httpApiType = builder.GetHttpApiType();

            if (httpApiType == null)
            {
                throw new InvalidOperationException($"无效的{nameof(IHttpClientBuilder)},找不到其关联的http接口类型");
            }

            return(builder.AddHttpMessageHandler(serviceProvider =>
            {
                var factory = serviceProvider.GetRequiredService <ITokenProviderFactory>();
                var tokenProvider = factory.Create(httpApiType, tokenProviderSearchMode);
                return handlerFactory(serviceProvider, tokenProvider);
            }));
        }
        /// <summary>
        /// Adds a <see cref="PolicyHttpMessageHandler"/> which will surround request execution with the provided
        /// <see cref="IAsyncPolicy"/>.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="policy">The <see cref="IAsyncPolicy"/>.</param>
        /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
        /// <remarks>
        /// <para>
        /// See the remarks on <see cref="PolicyHttpMessageHandler"/> for guidance on configuring policies.
        /// </para>
        /// </remarks>
        public static IHttpClientBuilder AddPolicyHandler(this IHttpClientBuilder builder, IAsyncPolicy policy)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (policy == null)
            {
                throw new ArgumentNullException(nameof(policy));
            }

            // Important - cache policy instances so that they are singletons per handler.
            var innerPolicy = policy.WrapAsync(Policy.NoOpAsync <HttpResponseMessage>());

            builder.AddHttpMessageHandler(() => new PolicyHttpMessageHandler(innerPolicy));
            return(builder);
        }
        public static IHttpClientBuilder AddAccessTokenPassThrough(this IHttpClientBuilder builder)
        {
            builder.Services
            .AddHttpContextAccessor()
            .AddPostConfigure <PassThroughTokenHandlerOptions, PostConfigurePassThroughAccessTokenHandlerOptions>();

            var instanceName = builder.Name;

            return(builder.AddHttpMessageHandler(sp =>
            {
                var optionsMonitor = sp.GetRequiredService <IOptionsMonitor <PassThroughTokenHandlerOptions> >();
                var options = optionsMonitor.Get(instanceName);

                return new PassThroughTokenHandler(
                    sp.GetRequiredService <IHttpContextAccessor>(),
                    options);
            }));
        }
예제 #11
0
        public static IHttpClientBuilder SendTraceIdentifiersFromHttpContext(this IHttpClientBuilder builder, Action <HttpRequestMessage, TraceIdentifiersContext> setupIdentifiers = null)
        {
            builder.AddHttpMessageHandler(configureHandler: provider =>
            {
                IHttpContextAccessor httpContextAccessor = provider.GetRequiredService <IHttpContextAccessor>();
                TraceIdentifiersContext context          = httpContextAccessor.HttpContext.Features.Get <TraceIdentifiersContext>();

                if (setupIdentifiers == null)
                {
                    return(new SendIdentifiersDelegatingHandler(request =>
                                                                request.TryAddLocalSharedAndRemoteShared(context, SendIdentifiersOptions.Default)));
                }

                return(new SendIdentifiersDelegatingHandler(request =>
                                                            setupIdentifiers.Invoke(request, context)));
            });

            return(builder);
        }
        /// <summary>
        /// Adds services required for adding correlation id to each outgoing <see cref="HttpClient"/> request.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/> to add the services to.</param>
        /// <param name="configureOptions">The action used to configure <see cref="CorrelateClientOptions"/>.</param>
        /// <returns>The <see cref="IHttpClientBuilder"/> so that additional calls can be chained.</returns>
        public static IHttpClientBuilder CorrelateRequests(this IHttpClientBuilder builder, Action <CorrelateClientOptions> configureOptions)
        {
            builder.Services.AddCorrelate();

            builder.Services.TryAddTransient <CorrelatingHttpMessageHandler>();
            builder.Services.Configure(builder.Name, configureOptions);
            builder.AddHttpMessageHandler(s =>
            {
                var allClientOptions  = s.GetRequiredService <IOptionsSnapshot <CorrelateClientOptions> >();
                var thisClientOptions = new OptionsWrapper <CorrelateClientOptions>(allClientOptions.Get(builder.Name));

                return(ActivatorUtilities.CreateInstance <CorrelatingHttpMessageHandler>(
                           s,
                           (IOptions <CorrelateClientOptions>)thisClientOptions
                           ));
            });

            return(builder);
        }
 public static IHttpClientBuilder AddTransientHttpError(this IHttpClientBuilder httpClient)
 {
     return(httpClient
            .AddHttpMessageHandler <CustomMessageHandler>()
            .AddTransientHttpErrorPolicy(policy =>
     {
         //return policy.WaitAndRetryAsync(3, i =>
         //{
         //    System.Diagnostics.Debug.WriteLine("11212");
         //    return TimeSpan.FromSeconds(300);
         //});
         return policy.OrResult(response => !response.IsSuccessStatusCode)
         .WaitAndRetryAsync(new[] {
             TimeSpan.FromSeconds(1), // 进行第一次重试之前延时1秒
             TimeSpan.FromSeconds(2), // 进行第二次重试之前延时2秒
             TimeSpan.FromSeconds(10),
         });
     }));
 }
        public static IHttpClientBuilder RegisterAndAddHttpMessageHandler <T>(this IHttpClientBuilder builder)
            where T : DelegatingHandler
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            builder.Services.TryAddTransient <T>();

            if (!builder.Services.Any(sd => sd.ServiceType == typeof(T) && sd.Lifetime == ServiceLifetime.Transient))
            {
                throw new InvalidOperationException($"An IServiceCollection registration for '{typeof(T).Name}' with the required transient service lifetime was not found and cannot be added.");
            }

            builder.AddHttpMessageHandler <T>();

            return(builder);
        }
        protected virtual void ConfigureHttpMessageHandlers(string serviceName, IServiceConfig serviceEndpoint, IHttpClientBuilder builder)
        {
            var retryPolicy = HttpPolicyExtensions
                              .HandleTransientHttpError()
                              .RetryAsync(TransientErrorRetryCount);

            var noOp = Policy.NoOpAsync().AsAsyncPolicy <HttpResponseMessage>();

            // IMPORTANT: This component should be only dependent on SingleInstance() components.
            // Transient instances may cause difficulties with tracing side effects raised by their
            // state or other transient deps (for example, per-request auth).
            // https://github.com/aspnet/HttpClientFactory/issues/198
            // https://github.com/aspnet/Docs/issues/9306

            builder
            .AddHttpMessageHandler <CorrelationIdHandler>()
            .AddHttpMessageHandler(services => new BearerAccessTokenHandler(services.GetRequiredService <IBearerTokenStorage>(), serviceEndpoint.ExcludeAccessToken))
            .AddPolicyHandler(request => request.Method == HttpMethod.Get || request.Method == HttpMethod.Head ? retryPolicy : noOp)
            .AddHttpMessageHandler <RequestResponseLoggingHandler>();
        }
예제 #16
0
        /// <summary>
        /// Adds a <see cref="PolicyHttpMessageHandler"/> which will surround request execution with a policy returned
        /// by the <paramref name="policySelector"/>.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="policySelector">
        /// Selects an <see cref="IAsyncPolicy{HttpResponseMessage}"/> to apply to the current request.
        /// </param>
        /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
        /// <remarks>
        /// <para>
        /// See the remarks on <see cref="PolicyHttpMessageHandler"/> for guidance on configuring policies.
        /// </para>
        /// </remarks>
        public static IHttpClientBuilder AddPolicyHandler(
            this IHttpClientBuilder builder,
            Func <IServiceProvider, HttpRequestMessage, IAsyncPolicy <HttpResponseMessage> > policySelector)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (policySelector == null)
            {
                throw new ArgumentNullException(nameof(policySelector));
            }

            builder.AddHttpMessageHandler((services) =>
            {
                return(new PolicyHttpMessageHandler((request) => policySelector(services, request)));
            });
            return(builder);
        }
        /// <summary>
        /// Adds the retry handler.
        /// </summary>
        /// <param name="builder">The builder.</param>
        /// <param name="configure">The configure.</param>
        /// <returns>IHttpClientBuilder.</returns>
        /// <exception cref="System.ArgumentNullException">builder</exception>
        /// <exception cref="System.ArgumentNullException">configure</exception>
        public static IHttpClientBuilder AddRetryHandler(this IHttpClientBuilder builder, Action <HttpRetryPolicyOptions> configure)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            HttpRetryPolicyOptions retryPolicyOptions = new HttpRetryPolicyOptions();

            configure(retryPolicyOptions);

            builder.AddHttpMessageHandler(() => new RetryDelegatingHandler(retryPolicyOptions));

            return(builder);
        }
예제 #18
0
        /// <summary>
        /// Registers an action to invoke before a <see cref="HttpRequestMessage"/> is sent by calling <see cref="HttpClientBuilderExtensions.AddHttpMessageHandler(IHttpClientBuilder, Func{IServiceProvider, DelegatingHandler})"/>.
        /// </summary>
        /// <param name="httpClientBuilder">The HTTP client builder </param>
        /// <param name="beforeSend">The action to invoke before sending the <see cref="HttpRequestMessage"/>.</param>
        /// <returns>The <see cref="IHttpClientBuilder"/> to use for further configuration.</returns>
        public static IHttpClientBuilder ForeachRequest(
            this IHttpClientBuilder httpClientBuilder,
            Action <HttpRequestMessage, CancellationToken> beforeSend
            )
        {
            if (httpClientBuilder == null)
            {
                throw new ArgumentNullException(nameof(httpClientBuilder));
            }
            if (beforeSend == null)
            {
                throw new ArgumentNullException(nameof(beforeSend));
            }

            httpClientBuilder
            .AddHttpMessageHandler(serviceProvider => new HttpClientDelegatingHandler(
                                       (serviceProvider, request, cancellationToken) => beforeSend.Invoke(request, cancellationToken)
                                       ));

            return(httpClientBuilder);
        }
        /// <summary>
        /// Adds an additional message handler from the dependency injection container for a named <see cref="HttpClient"/>
        /// AND registers it in the container with <see cref="ServiceLifetime.Transient"/> service lifetime.
        /// </summary>
        /// <typeparam name="THandler">The type of the <see cref="DelegatingHandler"/>.</typeparam>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="implementationFactory">The factory that creates the service, if any.</param>
        /// <returns>The updated <see cref="IHttpClientBuilder"/>.</returns>
        public static IHttpClientBuilder AddAndRegisterHttpMessageHandler <THandler>(
            this IHttpClientBuilder builder,
            Func <IServiceProvider, THandler> implementationFactory = null)
            where THandler : DelegatingHandler
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (implementationFactory == null)
            {
                builder.Services.TryAddTransient <THandler>();
            }
            else
            {
                builder.Services.TryAddTransient(implementationFactory);
            }

            return(builder.AddHttpMessageHandler <THandler>());
        }
예제 #20
0
        /// <summary>
        /// Adds a <see cref="PolicyHttpMessageHandler"/> which will surround request execution with a policy returned
        /// by the <see cref="IReadOnlyPolicyRegistry{String}"/>.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="policySelector">
        /// Selects an <see cref="IAsyncPolicy{HttpResponseMessage}"/> to apply to the current request.
        /// </param>
        /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
        /// <remarks>
        /// <para>
        /// See the remarks on <see cref="PolicyHttpMessageHandler"/> for guidance on configuring policies.
        /// </para>
        /// </remarks>
        public static IHttpClientBuilder AddPolicyHandlerFromRegistry(
            this IHttpClientBuilder builder,
            Func <IReadOnlyPolicyRegistry <string>, HttpRequestMessage, IAsyncPolicy <HttpResponseMessage> > policySelector)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (policySelector == null)
            {
                throw new ArgumentNullException(nameof(policySelector));
            }

            builder.AddHttpMessageHandler((services) =>
            {
                var registry = services.GetRequiredService <IReadOnlyPolicyRegistry <string> >();
                return(new PolicyHttpMessageHandler((request) => policySelector(registry, request)));
            });
            return(builder);
        }
예제 #21
0
        /// <summary>
        /// Adds a <see cref="PolicyHttpMessageHandler"/> which will surround request execution with a <see cref="Policy"/>
        /// created by executing the provided configuration delegate. The policy builder will be preconfigured to trigger
        /// application of the policy for requests that fail with conditions that indicate a transient failure.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="configurePolicy">A delegate used to create a <see cref="IAsyncPolicy{HttpResponseMessage}"/>.</param>
        /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
        /// <remarks>
        /// <para>
        /// See the remarks on <see cref="PolicyHttpMessageHandler"/> for guidance on configuring policies.
        /// </para>
        /// <para>
        /// The <see cref="PolicyBuilder{HttpResponseMessage}"/> provided to <paramref name="configurePolicy"/> has been
        /// preconfigured errors to handle errors in the following categories:
        /// <list type="bullet">
        /// <item><description>Network failures (as <see cref="HttpRequestException"/>)</description></item>
        /// <item><description>HTTP 5XX status codes (server errors)</description></item>
        /// <item><description>HTTP 408 status code (request timeout)</description></item>
        /// </list>
        /// </para>
        /// <para>
        /// The policy created by <paramref name="configurePolicy"/> will be cached indefinitely per named client. Policies
        /// are generally designed to act as singletons, and can be shared when appropriate. To share a policy across multiple
        /// named clients, first create the policy and then pass it to multiple calls to
        /// <see cref="AddPolicyHandler(IHttpClientBuilder, IAsyncPolicy{HttpResponseMessage})"/> as desired.
        /// </para>
        /// </remarks>
        public static IHttpClientBuilder AddTransientHttpErrorPolicy(
            this IHttpClientBuilder builder,
            Func <PolicyBuilder <HttpResponseMessage>, IAsyncPolicy <HttpResponseMessage> > configurePolicy)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (configurePolicy == null)
            {
                throw new ArgumentNullException(nameof(configurePolicy));
            }

            var policyBuilder = HttpPolicyExtensions.HandleTransientHttpError();

            // Important - cache policy instances so that they are singletons per handler.
            var policy = configurePolicy(policyBuilder);

            builder.AddHttpMessageHandler(() => new PolicyHttpMessageHandler(policy));
            return(builder);
        }
예제 #22
0
        /// <summary>
        /// Registers an action to invoke before a <see cref="HttpRequestMessage"/> is sent by calling <see cref="HttpClientBuilderExtensions.AddHttpMessageHandler(IHttpClientBuilder, Func{IServiceProvider, DelegatingHandler})"/>.
        /// </summary>
        /// <param name="httpClientBuilder">The HTTP client builder </param>
        /// <param name="beforeSend">The action to invoke before sending the <see cref="HttpRequestMessage"/>.</param>
        /// <returns>The <see cref="IHttpClientBuilder"/> to use for further configuration.</returns>
        public static IHttpClientBuilder ForeachRequest(
            this IHttpClientBuilder httpClientBuilder,
            Action <IServiceProvider, HttpRequestMessage, CancellationToken> beforeSend
            )
        {
            if (httpClientBuilder == null)
            {
                throw new ArgumentNullException(nameof(httpClientBuilder));
            }
            if (beforeSend == null)
            {
                throw new ArgumentNullException(nameof(beforeSend));
            }

            httpClientBuilder
            .AddHttpMessageHandler(serviceProvider => new HttpClientDelegatingHandler(
                                       beforeSend,
                                       () => serviceProvider.GetService <IHttpContextAccessor>()?.HttpContext?.RequestServices?.GetService <IServiceProvider>() ?? serviceProvider
                                       ));

            return(httpClientBuilder);
        }
예제 #23
0
        /// <summary>
        /// Adds a <see cref="PolicyHttpMessageHandler"/> which will surround request execution with a policy returned
        /// by the <see cref="IReadOnlyPolicyRegistry{String}"/>.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="policyKey">
        /// The key used to resolve a policy from the <see cref="IReadOnlyPolicyRegistry{String}"/>.
        /// </param>
        /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns>
        /// <remarks>
        /// <para>
        /// See the remarks on <see cref="PolicyHttpMessageHandler"/> for guidance on configuring policies.
        /// </para>
        /// </remarks>
        public static IHttpClientBuilder AddPolicyHandlerFromRegistry(this IHttpClientBuilder builder, string policyKey)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (policyKey == null)
            {
                throw new ArgumentNullException(nameof(policyKey));
            }

            builder.AddHttpMessageHandler((services) =>
            {
                var registry = services.GetRequiredService <IReadOnlyPolicyRegistry <string> >();

                var policy = registry.Get <IAsyncPolicy <HttpResponseMessage> >(policyKey);

                return(new PolicyHttpMessageHandler(policy));
            });
            return(builder);
        }
        /// <summary>
        /// Adds a <see cref="HttpTracingDelegatingHandler"/> to enable tracing of requests/responses.
        /// </summary>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param>
        /// <param name="categoryName">
        /// The category name to use for logging.
        /// Defaults to "System.Net.Http.HttpClient.{HttpClient.Name}.TraceHandler".</param>
        /// <param name="isResponseSuccessful">
        /// A function to allow customization of the evaluation of a successful response.
        /// Defaults to <see cref="HttpResponseMessage.IsSuccessStatusCode"/>.
        /// </param>
        /// <param name="bufferRequests">
        /// When set to true, will actively buffer the requests bodies.
        /// This is to be used when you want to see the content of requests
        /// when using serializer that are forward-only.
        /// This will impact performance and memory consumption, but is probably fine if you are
        /// in a typical run-of-the-mill scenario.
        /// </param>
        /// <param name="logger">
        /// Use a custom <see cref="ILogger"/> instead of the one provided by the <see cref="ILoggerFactory"/>.
        /// When used, the <paramref name="categoryName"/> is ineffective.
        /// </param>
        /// <returns>The updated <see cref="IHttpClientBuilder"/>.</returns>
        public static IHttpClientBuilder AddHttpTracing(
            this IHttpClientBuilder builder,
            string categoryName = null,
            Func <HttpResponseMessage, bool> isResponseSuccessful = null,
            bool bufferRequests = false,
            ILogger logger      = null)
        {
            if (builder is null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (string.IsNullOrEmpty(categoryName))
            {
                categoryName = HttpTracingDelegatingHandler.LoggerCategory(builder.Name);
            }

            return(builder.AddHttpMessageHandler(
                       sp => new HttpTracingDelegatingHandler(
                           logger: logger ?? sp.GetRequiredService <ILoggerFactory>().CreateLogger(categoryName),
                           isResponseSuccessful: isResponseSuccessful,
                           bufferRequests: bufferRequests)));
        }
예제 #25
0
        /// <summary>
        /// Adds a message handler for propagating headers collected by the <see cref="HeaderPropagationMiddleware"/> to a outgoing request,
        /// explicitly specifying which headers to propagate.
        /// </summary>
        /// <remarks>This also allows to redefine the name to use for a header in the outgoing request.</remarks>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/> to add the message handler to.</param>
        /// <param name="configure">A delegate used to configure the <see cref="HeaderPropagationMessageHandlerOptions"/>.</param>
        /// <returns>The <see cref="IHttpClientBuilder"/> so that additional calls can be chained.</returns>
        public static IHttpClientBuilder AddHeaderPropagation(this IHttpClientBuilder builder, Action <HeaderPropagationMessageHandlerOptions> configure)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            builder.Services.AddHeaderPropagation();

            builder.AddHttpMessageHandler(services =>
            {
                var options = new HeaderPropagationMessageHandlerOptions();
                configure(options);
                return(new HeaderPropagationMessageHandler(options, services.GetRequiredService <HeaderPropagationValues>()));
            });

            return(builder);
        }
예제 #26
0
        /// <summary>
        /// Adds a message handler for propagating headers collected by the <see cref="HeaderPropagationMiddleware"/> to a outgoing request.
        /// </summary>
        /// <remarks>
        /// When using this method, all the configured headers will be applied to the outgoing HTTP requests.
        /// </remarks>
        /// <param name="builder">The <see cref="IHttpClientBuilder"/> to add the message handler to.</param>
        /// <returns>The <see cref="IHttpClientBuilder"/> so that additional calls can be chained.</returns>
        public static IHttpClientBuilder AddHeaderPropagation(this IHttpClientBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            builder.Services.AddHeaderPropagation();

            builder.AddHttpMessageHandler(services =>
            {
                var options           = new HeaderPropagationMessageHandlerOptions();
                var middlewareOptions = services.GetRequiredService <IOptions <HeaderPropagationOptions> >();
                for (var i = 0; i < middlewareOptions.Value.Headers.Count; i++)
                {
                    var header = middlewareOptions.Value.Headers[i];
                    options.Headers.Add(header.CapturedHeaderName, header.CapturedHeaderName);
                }
                return(new HeaderPropagationMessageHandler(options, services.GetRequiredService <HeaderPropagationValues>()));
            });

            return(builder);
        }
        /// <summary>
        /// Add logging handler to HttpClient
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="adjustSettings"></param>
        /// <returns></returns>
        public static IHttpClientBuilder AddLoggingHandler(
            this IHttpClientBuilder builder,
            Action <LoggingHttpHandler.Settings>?adjustSettings = null)
        {
            var name     = builder.Name;
            var settings = new LoggingHttpHandler.Settings();

            adjustSettings?.Invoke(settings);

            if (settings.LogBody == null)
            {
                throw new ArgumentException($"{nameof(settings.LogBody)} can't be null");
            }
            if (settings.LogLevel == null)
            {
                throw new ArgumentException($"{nameof(settings.LogLevel)} can't be null");
            }
            if (settings.LogLevelException == null)
            {
                throw new ArgumentException($"{nameof(settings.LogLevelException)} can't be null");
            }

            return(builder.AddHttpMessageHandler(sp => new LoggingHttpHandler(sp.GetRequiredService <ILoggerFactory>(), name, settings)));
        }
 public static IHttpClientBuilder AddDevspacesSupport(this IHttpClientBuilder builder)
 {
     builder.AddHttpMessageHandler <DevspacesMessageHandler>();
     return(builder);
 }
예제 #29
0
 /// <summary>
 /// Adds a delegate handler to audit HttpClient calls.
 /// </summary>
 /// <param name="builder">The Microsoft.Extensions.DependencyInjection.IHttpClientBuilder</param>
 /// <param name="config">The audit configuration</param>
 /// <returns></returns>
 public static IHttpClientBuilder AddAuditHandler(this IHttpClientBuilder builder, Action <ConfigurationApi.IAuditClientHandlerConfigurator> config)
 {
     return(builder.AddHttpMessageHandler(() => new AuditHttpClientHandler(config, null)));
 }
 /// <summary>
 /// Adds the user access token handler to an HttpClient
 /// </summary>
 /// <param name="httpClientBuilder"></param>
 /// <returns></returns>
 public static IHttpClientBuilder AddUserAccessTokenHandler(this IHttpClientBuilder httpClientBuilder)
 {
     return(httpClientBuilder.AddHttpMessageHandler <UserAccessTokenHandler>());
 }