C# 如何使用RateLimitor';带依赖项注入的HttpClient DelegatingHandler?

C# 如何使用RateLimitor';带依赖项注入的HttpClient DelegatingHandler?,c#,.net-core,dependency-injection,dotnet-httpclient,C#,.net Core,Dependency Injection,Dotnet Httpclient,我已经在我的项目中成功地使用()有一段时间了。我最近发现了依赖项注入,并试图按原样迁移我的代码以使用它,但我仍停留在RateLimiter上 文档的正常使用是 var handler = TimeLimiter .GetFromMaxCountByInterval(25, TimeSpan.FromMinutes(1)) .AsDelegatingHandler(); var Client = new HttpClient(handler) 但是,如果我在依赖项

我已经在我的项目中成功地使用()有一段时间了。我最近发现了依赖项注入,并试图按原样迁移我的代码以使用它,但我仍停留在RateLimiter上

文档的正常使用是

var handler = TimeLimiter
        .GetFromMaxCountByInterval(25, TimeSpan.FromMinutes(1))
        .AsDelegatingHandler();
var Client = new HttpClient(handler)
但是,如果我在依赖项注入期间尝试复制它

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient<IMyApiClient, MyApiClient>(client => client.BaseAddress = new Uri("https://api.myapi.com/"))
               .AddPolicyHandler(GetRetryPolicy())
               .AddHttpMessageHandler(() => TimeLimiter.GetFromMaxCountByInterval(25, TimeSpan.FromMinutes(1)).AsDelegatingHandler());
     }
我的类客户机结构(主要是为了单元测试)如下所示:

using System.Net.Http;
using System.Threading.Tasks;

public class MyApiClient : HumbleHttpClient, IMyApiClient
{
    public MyApiClient(HttpClient client)
        : base(client)
    {
    }
}

public class HumbleHttpClient : IHttpClient
{
    public HumbleHttpClient(HttpClient httpClient)
    {
        this.Client = httpClient;
    }

    public HttpClient Client { get; }

    public Task<HttpResponseMessage> GetAsync(string requestUri)
    {
        return this.Client.GetAsync(requestUri);
    }

    public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
    {
        return this.Client.PostAsync(requestUri, content);
    }
}

public interface IHttpClient
{
    Task<HttpResponseMessage> GetAsync(string requestUri);
    Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
    HttpClient Client { get; }
}
使用System.Net.Http;
使用System.Threading.Tasks;
公共类MyapClient:HumbleHttpClient,IMyApiClient
{
公共MyApiClient(HttpClient)
:基本(客户端)
{
}
}
公共类HumbleHttpClient:IHttpClient
{
公共HumbleHttpClient(HttpClient HttpClient)
{
this.Client=httpClient;
}
公共HttpClient客户端{get;}
公共任务GetAsync(字符串请求URI)
{
返回this.Client.GetAsync(requestUri);
}
公共任务PostAsync(字符串请求URI、HttpContent)
{
返回this.Client.PostAsync(requestUri,content);
}
}
公共接口IHttpClient
{
任务GetAsync(字符串请求URI);
任务PostAsync(字符串requestUri、HttpContent);
HttpClient客户端{get;}
}
以下是我一直试图遵循的文档:

我不知道这是一个bug还是一个特性,但要解决这个问题,我相信您还需要添加委派处理程序

因此,在一个典型的场景中,您需要设置一个
DelegatingHandler
,如下所示:

公共密封类MyDelegatingHandler:DelegatingHandler
{
// ...
}
然后你需要注册它;但问题是。。。您还需要将处理程序注册为瞬态:

公共覆盖无效配置(IFunctionsHostBuilder)
{
builder.Services.AddHttpClient()
.AddHttpMessageHandler();
//这需要补充:
builder.Services.AddTransient();
}
话虽如此,但由于要使用的处理程序是在运行时从第三方创建的,因此您处于一种独特的情况。你可以让它工作。。。如果它是正确的,则不是100%,但它应该可以工作:

公共覆盖无效配置(IFunctionsHostBuilder)
{
var handler=TimeLimiter
.GetFromMaxCountByInterval(25,TimeSpan.FromMinutes(1))
.AsDelegatingHandler();
builder.Services.AddHttpClient(
client=>client.BaseAddress=新Uri(“https://api.myapi.com/"))
.AddPolicyHandler(GetRetryPolicy())
.AddHttpMessageHandler(()=>handler);
builder.Services.AddTransient(=>handler);
}
编辑以添加。。。 您看到的问题是
ComposableAsync
Nuget包。明确地代码不应设置此属性。ASP.NET Core应该/将这样做。幸运的是,这只是一个简单的扩展方法

让我们编写自己的扩展,以正确的方式进行扩展:

使用System.Net.Http;
使用系统线程;
使用System.Threading.Tasks;
名称空间YourNamespace
{
公共静态类DispatcherExtension
{
私人密封类调度员DelegatingHandler:DelegatingHandler
{
专用只读ComposableAsync.IDispatcher\u调度程序;
公共调度员DelegatingHandler(ComposableAsync.IDispatcher调度员)
{
_调度员=调度员;
}
受保护的覆盖任务SendAsync(
HttpRequestMessage请求,
取消令牌(取消令牌)
{
return _Dispatcher.Enqueue(()=>
base.sendaync(请求、取消令牌)、取消令牌);
}
}
公共静态DelegatingHandler作为DelegatingHandler(
此ComposableAsync.IDispatcher(调度程序)
{
返回新的DispatcherDelegatingHandler(调度员);
}
}
}
请务必将您的代码更改为我在上面注册hander时的代码。另外,确保它使用的是新的扩展名,而不是库中的扩展名

我测试了它,您可以看到它设置正确:


我也会考虑在CyrabaseSycGITHUB页面中打开一个bug。

这是一个很好的想法,但是我仍然受到错误的影响:“InnHand程序属性不能是NULL”。我认为我使用的NuGuT包是错误的。在它们的构造函数中,它们显式地设置了InnerHandler,这可能是这个问题的根源。public DispatcherDelegatingHandler(IDispatcher dispatcher){this.u dispatcher=dispatcher;this.InnerHandler=(HttpMessageHandler)new HttpClientHandler();}@Lukeschoon--所以问题是。他不应该这么做。ASP.NET核心集。@Lukeschoon——更新的答案。这应该可以解决问题。
using System.Net.Http;
using System.Threading.Tasks;

public class MyApiClient : HumbleHttpClient, IMyApiClient
{
    public MyApiClient(HttpClient client)
        : base(client)
    {
    }
}

public class HumbleHttpClient : IHttpClient
{
    public HumbleHttpClient(HttpClient httpClient)
    {
        this.Client = httpClient;
    }

    public HttpClient Client { get; }

    public Task<HttpResponseMessage> GetAsync(string requestUri)
    {
        return this.Client.GetAsync(requestUri);
    }

    public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
    {
        return this.Client.PostAsync(requestUri, content);
    }
}

public interface IHttpClient
{
    Task<HttpResponseMessage> GetAsync(string requestUri);
    Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
    HttpClient Client { get; }
}