ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

http request middleware & Polly handlers & DI in .NetCore

2022-07-11 18:03:19  阅读:270  来源: 互联网

标签:Polly http handlers builder request handler Services


Make HTTP requests using IHttpClientFactory in ASP.NET Core | Microsoft Docs

 

HttpClient has the concept of delegating handlers that can be linked together for outgoing HTTP requests. IHttpClientFactory:

  • Simplifies defining the handlers to apply for each named client.
  • Supports registration and chaining of multiple handlers to build an outgoing request middleware pipeline. Each of these handlers is able to perform work before and after the outgoing request. This pattern:
    • Is similar to the inbound middleware pipeline in ASP.NET Core.
    • Provides a mechanism to manage cross-cutting concerns around HTTP requests, such as:
      • caching
      • error handling
      • serialization
      • logging

 

 

To create a delegating handler:

  • Derive from DelegatingHandler.
  • Override SendAsync. Execute code before passing the request to the next handler in the pipeline:

 

public class ValidateHeaderHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (!request.Headers.Contains("X-API-KEY"))
        {
            return new HttpResponseMessage(HttpStatusCode.BadRequest)
            {
                Content = new StringContent(
                    "The API key header X-API-KEY is required.")
            };
        }

        return await base.SendAsync(request, cancellationToken);
    }
}

  

The preceding code checks if the X-API-KEY header is in the request. If X-API-KEY is missing, BadRequest is returned.

More than one handler can be added to the configuration for an HttpClient with Microsoft.Extensions.DependencyInjection.HttpClientBuilderExtensions.AddHttpMessageHandler:

 

builder.Services.AddTransient<ValidateHeaderHandler>();

builder.Services.AddHttpClient("HttpMessageHandler")
    .AddHttpMessageHandler<ValidateHeaderHandler>();

  

In the preceding code, the ValidateHeaderHandler is registered with DI. Once registered, AddHttpMessageHandler can be called, passing in the type for the handler.

Multiple handlers can be registered in the order that they should execute. Each handler wraps the next handler until the final HttpClientHandler executes the request:

builder.Services.AddTransient<SampleHandler1>();
builder.Services.AddTransient<SampleHandler2>();

builder.Services.AddHttpClient("MultipleHttpMessageHandlers")
    .AddHttpMessageHandler<SampleHandler1>()
    .AddHttpMessageHandler<SampleHandler2>();

  In the preceding code, SampleHandler1 runs first, before SampleHandler2.

 

Use DI in outgoing request middleware

When IHttpClientFactory creates a new delegating handler, it uses DI to fulfill the handler's constructor parameters. IHttpClientFactory creates a separate DI scope for each handler, which can lead to surprising behavior when a handler consumes a scoped service.

For example, consider the following interface and its implementation, which represents a task as an operation with an identifier, OperationId:

public interface IOperationScoped
{
    string OperationId { get; }
}

public class OperationScoped : IOperationScoped
{
    public string OperationId { get; } = Guid.NewGuid().ToString()[^4..];
}

  

As its name suggests, IOperationScoped is registered with DI using a scoped lifetime:

builder.Services.AddScoped<IOperationScoped, OperationScoped>();

  

The following delegating handler consumes and uses IOperationScoped to set the X-OPERATION-ID header for the outgoing request:

 

 

 

 

In the HttpRequestsSample download, navigate to /Operation and refresh the page. The request scope value changes for each request, but the handler scope value only changes every 5 seconds.

Handlers can depend upon services of any scope. Services that handlers depend upon are disposed when the handler is disposed.

Use one of the following approaches to share per-request state with message handlers:

 

Use Polly-based handlers

IHttpClientFactory integrates with the third-party library Polly. Polly is a comprehensive resilience and transient fault-handling library for .NET. It allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner.

Extension methods are provided to enable the use of Polly policies with configured HttpClient instances. The Polly extensions support adding Polly-based handlers to clients. Polly requires the Microsoft.Extensions.Http.Polly NuGet package.

 

Handle transient faults

Faults typically occur when external HTTP calls are transient. AddTransientHttpErrorPolicy allows a policy to be defined to handle transient errors. Policies configured with AddTransientHttpErrorPolicy handle the following responses:

AddTransientHttpErrorPolicy provides access to a PolicyBuilder object configured to handle errors representing a possible transient fault:

builder.Services.AddHttpClient("PollyWaitAndRetry")
    .AddTransientHttpErrorPolicy(policyBuilder =>
        policyBuilder.WaitAndRetryAsync(
            3, retryNumber => TimeSpan.FromMilliseconds(600)));

  In the preceding code, a WaitAndRetryAsync policy is defined. Failed requests are retried up to three times with a delay of 600 ms between attempts.

 

Dynamically select policies

Extension methods are provided to add Polly-based handlers, for example, AddPolicyHandler. The following AddPolicyHandler overload inspects the request to decide which policy to apply:

var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
    TimeSpan.FromSeconds(10));
var longTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
    TimeSpan.FromSeconds(30));

builder.Services.AddHttpClient("PollyDynamic")
    .AddPolicyHandler(httpRequestMessage =>
        httpRequestMessage.Method == HttpMethod.Get ? timeoutPolicy : longTimeoutPolicy);

  In the preceding code, if the outgoing request is an HTTP GET, a 10-second timeout is applied. For any other HTTP method, a 30-second timeout is used.

 

 

Add multiple Polly handlers

It's common to nest Polly policies:

builder.Services.AddHttpClient("PollyMultiple")
    .AddTransientHttpErrorPolicy(policyBuilder =>
        policyBuilder.RetryAsync(3))
    .AddTransientHttpErrorPolicy(policyBuilder =>
        policyBuilder.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));

  

In the preceding example:

  • Two handlers are added.
  • The first handler uses AddTransientHttpErrorPolicy to add a retry policy. Failed requests are retried up to three times.
  • The second AddTransientHttpErrorPolicy call adds a circuit breaker policy. Further external requests are blocked for 30 seconds if 5 failed attempts occur sequentially. Circuit breaker policies are stateful. All calls through this client share the same circuit state.

 

Add policies from the Polly registry

An approach to managing regularly used policies is to define them once and register them with a PolicyRegistry. For example:

var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
    TimeSpan.FromSeconds(10));
var longTimeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(
    TimeSpan.FromSeconds(30));

var policyRegistry = builder.Services.AddPolicyRegistry();

policyRegistry.Add("Regular", timeoutPolicy);
policyRegistry.Add("Long", longTimeoutPolicy);

builder.Services.AddHttpClient("PollyRegistryRegular")
    .AddPolicyHandlerFromRegistry("Regular");

builder.Services.AddHttpClient("PollyRegistryLong")
    .AddPolicyHandlerFromRegistry("Long");

  

In the preceding code:

  • Two policies, Regular and Long, are added to the Polly registry.
  • AddPolicyHandlerFromRegistry configures individual named clients to use these policies from the Polly registry.

For more information on IHttpClientFactory and Polly integrations, see the Polly wiki.

 

标签:Polly,http,handlers,builder,request,handler,Services
来源: https://www.cnblogs.com/panpanwelcome/p/16467316.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有