使用 HttpClient 子类的类型化客户端

kar*_*llo 3 c# dependency-injection asp.net-core

在我的应用程序中,我将有很少的 TypedClient 服务。然而,这些类将共享一堆方法。我对此的解决方案是创建 CustomHttpClient:

public class CustomHttpClient:HttpClient
{
  //here shared methods
}
Run Code Online (Sandbox Code Playgroud)

然后我的类型化客户端类将使用这个派生类而不是标准的 HttpClient:

public class MyService : IMyService
{
  public SomeService(CustomHttpClient client, IConfiguration configuration){}
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试在启动时注册此服务,我会收到一个错误,指出没有合适的 'MyService' 构造函数:

services.AddHttpClient<IMyService, MyService>();
Run Code Online (Sandbox Code Playgroud)

在我发现的文档中:

Typed Client 是一个类,它接受一个 HttpClient 对象(通过其构造函数注入)并使用它来调用一些远程 HTTP 服务

这是否意味着它不能接受 HttpClient 的子类?如果是这种情况,那么我唯一的解决方案就是将共享方法实现为 HttpClient 扩展方法(我真的不喜欢这个解决方案)。是否有解决方法,或者扩展方法是我唯一的出路?我也尝试注册 CustomHttpClient 以便 DI 容器会找到它,但错误仍然相同。你能给我什么建议?

Dav*_*oft 5

这是否意味着它不能接受 HttpClient 的子类?

是的。

如果是这种情况,那么我唯一的解决方案是将共享方法实现为 HttpClient 扩展方法

不。根据文档类型化的客户端封装了一个 HttpClient,而不是扩展它。您在构造函数中配置 HttpClient,然后将自定义方法添加到使用封装的 HttpClient 实例的 Typed Client。

如果您不想将框架的模式用于 HttpClient 处理,您可以自由创建自己的模式,但这可能不值得付出努力。

您可以拥有共享基类的类型化客户端。例如

public class MyBaseTypedClient
{
    public HttpClient Client { get; }

    public MyBaseTypedClient(HttpClient client)
    {
        client.BaseAddress = new Uri("https://api.github.com/");
        // GitHub API versioning
        client.DefaultRequestHeaders.Add("Accept",
            "application/vnd.github.v3+json");
        // GitHub requires a user-agent
        client.DefaultRequestHeaders.Add("User-Agent",
            "HttpClientFactory-Sample");

        Client = client;
    }

    //other methods

}
public class MyTypedClient : MyBaseTypedClient
{
    public MyTypedClient(HttpClient client) : base(client) { }
}
Run Code Online (Sandbox Code Playgroud)

  • 类型化客户端不应该“成为”客户端(is-a),而应该“拥有”(has-a)客户端。它们都可以有一个共同的基础,但与 HttpClient 的关系应该是所有权而不是继承。例如, HttpClientFactory 对 HttpClient 的子类一无所知,因此如果您需要它,您必须完全重写该逻辑(并且您隐式地这样做,因为您正在尝试使用 http 客户端注入),而对于所有权模式它所要做的就是将普通客户端注入到其他容器中。 (2认同)