简体   繁体   English

将 DelegatingHandler 与 HttpClient 上的自定义数据一起使用

[英]Using DelegatingHandler with custom data on HttpClient

Given the well known dilemma's and issues of using HttpClient - namely socket exhaustion and not respecting DNS updates, its considered best practice to use IHttpClientFactory and let the container decide when and how to utilise http pool connections efficiency.鉴于众所周知的使用 HttpClient 的困境和问题 - 即套接字耗尽和不尊重 DNS 更新,它被认为是使用 IHttpClientFactory 并让容器决定何时以及如何使用 http 池连接效率的最佳实践。 Which is all good, but now I cannot instantiate a custom DelegatingHandler with custom data on each request.这一切都很好,但现在我无法在每个请求上使用自定义数据实例化自定义 DelegatingHandler。

Sample below on how I did it before using the factory method:下面的示例说明我在使用工厂方法之前是如何做到的:

public class HttpClientInterceptor : DelegatingHandler
{
    private readonly int _id;
    public HttpClientInterceptor(int id)
    {
        _id = id;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // associate the id with this request
        Database.InsertEnquiry(_id, request);
        return await base.SendAsync(request, cancellationToken);
    }
}

For every time I instantiate a HttpClient a Id can be passed along:每次我实例化一个 HttpClient 时,都可以传递一个 Id:

public void DoEnquiry()
{
    // Insert a new enquiry hypothetically 
    int id = Database.InsertNewEnquiry();
    using (var http = new HttpClient(new HttpClientInterceptor(id)))
    {
        // and do some operations on the http client
        // which will be logged in the database associated with id
        http.GetStringAsync("http://url.com");
    }
}

But now I cannot instantiate the HttpClient nor the Handlers.但现在我无法实例化 HttpClient 或处理程序。

public void DoEnquiry(IHttpClientFactory factory)
{
    int id = Database.InsertNewEnquiry();
    var http = factory.CreateClient();
    // and now??

    http.GetStringAsync("http://url.com");
}

How would I be able to achieve similar using the factory?我如何能够使用工厂实现类似的目标?

I cannot instantiate a custom DelegatingHandler with custom data on each request.我无法在每个请求上使用自定义数据实例化自定义 DelegatingHandler。

This is correct.这是对的。 But you can use a custom DelegatingHandler that is reusable (and stateless), and pass the data as part of the request.但是您可以使用可重用(且无状态)的自定义DelegatingHandler ,并将数据作为请求的一部分传递。 This is what HttpRequestMessage.Properties is for.这就是HttpRequestMessage.Properties的用途。 When doing these kinds of "custom context" operations, I prefer to define my context "property" as an extension method:在进行这些类型的“自定义上下文”操作时,我更喜欢将我的上下文“属性”定义为扩展方法:

public static class HttpRequestExtensions
{
  public static HttpRequestMessage WithId(this HttpRequestMessage request, int id)
  {
    request.Properties[IdKey] = id;
    return request;
  }

  public static int? TryGetId(this HttpRequestMessage request)
  {
    if (request.Properties.TryGetValue(IdKey, out var value))
      return value as int?;
    return null;
  }

  private static readonly string IdKey = Guid.NewGuid().ToString("N");
}

Then you can use it as such in a (reusable) DelegatingHandler :然后你可以在(可重用的) DelegatingHandler中使用它:

public class HttpClientInterceptor : DelegatingHandler
{
  protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  {
    var id = request.TryGetId();
    if (id == null)
      throw new InvalidOperationException("This request must have an id set.");

    // associate the id with this request
    Database.InsertEnquiry(id.Value, request);
    return await base.SendAsync(request, cancellationToken);
  }
}

The disadvantage to this approach is that each callsite then has to specify the id.这种方法的缺点是每个调用站点都必须指定 id。 This means you can't use the built-in convenience methods like GetStringAsync ;这意味着您不能使用像GetStringAsync这样的内置便利方法; if you do, the exception above will be thrown.如果你这样做,上面的异常将被抛出。 Instead, your code will have to use the lower-level SendAsync method:相反,您的代码将不得不使用较低级别的SendAsync方法:

var request = new HttpRequestMessage(HttpMethod.Get, "http://url.com");
request.SetId(id);
var response = await client.SendAsync(request);

The calling boilerplate is rather ugly.调用样板相当难看。 You can wrap this up into your own GetStringAsync convenience method;您可以将其包装到您自己的GetStringAsync便捷方法中; something like this should work:像这样的东西应该工作:

public static class HttpClientExtensions
{
  public static async Task<string> GetStringAsync(int id, string url)
  {
    var request = new HttpRequestMessage(HttpMethod.Get, url);
    request.SetId(id);
    var response = await client.SendAsync(request);
    return await response.Content.ReadAsStringAsync();
  }
}

and now your call sites end up looking cleaner again:现在您的呼叫站点最终看起来又干净了:

public async Task DoEnquiry(IHttpClientFactory factory)
{
  int id = Database.InsertNewEnquiry();
  var http = factory.CreateClient();
  var result = await http.GetStringAsync(id, "http://url.com");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 改装 HttpClient 不添加 DelegatingHandler - Refit HttpClient not adding DelegatingHandler 循环中的 DelegatingHandler 和 HttpClient - DelegatingHandler and HttpClient in a loop 在 Windows 窗体的 HttpClient 类中使用 DelegatingHandler - 尚未设置内部处理程序 - Using a DelegatingHandler in HttpClient class from windows forms - Inner handler has not been set 如何为自定义路由定义DelegatingHandler? - How to define a DelegatingHandler for custom route? 在DelegatingHandler中使用HttpClient时出错:请求消息已发送。 无法多次发送相同的请求消息 - Error when using HttpClient inside DelegatingHandler: The request message was already sent. Cannot send the same request message multiple times 在MVC中使用Web API DelegatingHandler - Using Web API DelegatingHandler in MVC 使用DelegatingHandler包装WebApi响应 - Wrapping WebApi responses using DelegatingHandler 具有双向TLS和DelegatingHandler的HttpClient用于记录请求/响应引发异常 - HttpClient with Mutual TLS and DelegatingHandler for logging request/response throws exception 测试时HttpClient.SendAsync不使用DelegatingHandler - HttpClient.SendAsync doesn't use DelegatingHandler when testing 如何将 RateLimiter 的 HttpClient DelegatingHandler 与依赖注入一起使用? - How can I use RateLimiter's HttpClient DelegatingHandler with dependency injection?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM