C# 注入的HttpClient忽略IHttpClientFactory配置

C# 注入的HttpClient忽略IHttpClientFactory配置,c#,dependency-injection,dotnet-httpclient,C#,Dependency Injection,Dotnet Httpclient,我创建了一个自定义库,它可以自动为依赖于HttpClient的特定服务设置Polly策略 这是使用扩展方法和类型化客户端方法来完成的。一个简化的例子: 公共静态IHttpClientBuilder设置FooServiceHttpClient(此IServiceCollection服务) { 回程服务 .AddHttpClient() .AddPolicyHandler(GetRetryPolicy()); } 示例服务: 公共类服务 { 私有只读HttpClient\u客户端; //选择1

我创建了一个自定义库,它可以自动为依赖于
HttpClient
的特定服务设置Polly策略

这是使用扩展方法和类型化客户端方法来完成的。一个简化的例子:

公共静态IHttpClientBuilder设置FooServiceHttpClient(此IServiceCollection服务)
{
回程服务
.AddHttpClient()
.AddPolicyHandler(GetRetryPolicy());
} 
示例服务:

公共类服务
{
私有只读HttpClient\u客户端;
//选择1
公共服务(HttpClient HttpClient)
{
_client=httpClient;
}
//选择2
公共食品服务(IHttpClientFactory httpClientFactory)
{
_client=httpClientFactory.CreateClient(GetType().Name);
}
公共职务
{
var test=\u client.GetAsync(“http://example.com");
}
}
从DI容器(这是从测试项目)获取服务:

var services=newservicecolection();
SetUpFooServiceHttpClient();
services.AddSingleton();
var fooService=服务
.BuildServiceProvider()
.GetRequiredService();
//执行测试
fooService.DoJob();
注意:在这个测试项目中,我还添加了一个额外的模拟处理程序,因为我试图模拟http状态响应,但是模拟处理程序是否存在与Polly策略是否存在完全相同,所以我在示例代码中省略了模拟处理程序

请注意
FooService
中的两个不同构造函数。根据我对哪一个进行了评论和留下了哪一个,我会得到不同的结果。所有其他代码保持不变

  • 选项1,直接注入
    HttpClient
    ,忽略我的所有配置。我得到了一个没有Polly策略处理程序的标准http客户机
  • 选项2,注入
    IHttpClientFactory
    并使用当前类型名称请求客户端(即
    FooService
    )符合我的配置。我得到一个自定义http客户端,其中包含Polly策略处理程序(以及我可能配置的任何其他处理程序,例如测试套件中的模拟处理程序)
在这两种情况下,都使用调试检查来确认策略处理程序是否存在

根据我在这个主题上找到的所有文档,这两个选项应该是等效的,至少对于我最终获得的构建的
HttpClient
。但事实并非如此

我找到的文档指定在使用类型化的客户端时可以注入
HttpClient

  • 例如,“类型化客户机”部分
  • 这个
  • 这个
我使用的是类型化客户端,但注入
HttpClient
显然不适合我


为什么注入
HttpClient
与注入
IHttpClientFactory
在我的情况下效果不同?

实际上,您的
FooService
类有以下两种注册:

  • services.AddHttpClient()
  • services.AddSingleton()

  • 由于DI容器在幕后的工作方式,第二次注册覆盖了第一次注册。如果删除第二个注册,将使用第一个注册,因此将调用带有
    HttpClient
    参数的构造函数。

    remove
    services.AddSingleton()-您不需要它,它实际上覆盖了前面的
    AddTypedClient
    调用完成的一些配置。“我想这可能就是你们所需要解决的所有问题了。”柯克拉金奖得主,鸡肉晚餐!发布一个答案,我会在可能的时候接受+赏金。这确实让事情有点复杂,因为这意味着我的图书馆的消费者不允许建立他们自己的服务。当他们想要注册
    ,以及整个作用域/瞬态/单例逻辑时,这会很烦人。反转两行(而不是删除一行)会起作用吗?只是为了兴趣。@mjwills:它确实有效,但第一行实际上被忽略了。刚刚通过设置调试值对其进行了测试,我注意到在添加类型化客户端之后,我预先设置的任何
    FooService
    依赖项配置都不再存在,注入的依赖项是“默认”的
    FooService
    实例,注入了正确的httpclient。总的来说,DI框架的行为感觉比它应该的更挑剔,但至少它现在可以工作:)只是为了稍微扩展一下,为将来的读者,通过删除
    AddSingleton
    行,
    HttpClient
    方法是固定的,但是
    IHttpClientFactory
    方法中断了。您应该仅为那些依赖于
    IHttpClientFactory
    的类调用
    AddSingleton
    (及类似)。