ASP.NET Core 2.1のHttpClientFactory(Part 2)は、ネーミングおよびタイプ化されたクライアントを定義します.

15187 ワード

原文:https://www.stevejgordon.co.uk/httpclientfactory-named-typed-clients-aspnetcore発表:2018年1月
前の記事「HttpClientFactory概要」では、この機能を作成した理由を説明しています.解決できる問題を知り、WebAPIアプリケーションでどのように使用するかを示す非常に基本的な例を挙げました.この文章では、ネーミングクライアント(named clients)とタイプ化クライアント(typed clients)の2つの方法を深く検討したいと思います.

名前付きクライアント(Name Clients)


最初の記事では、HttpClientFactoryを使用して基本的なHttpClientインスタンスを取得する方法を説明しました.これは、単一の場所から高速リクエストを発行するだけでよいです.しかし、通常、コード内の複数の場所から同じサービスに複数のリクエストを送信することができます.クライアントの概念をネーミングすることで、HttpClientFactoryはこの点をより容易にします.名前付きクライアントを使用すると、HttpClientの作成時の特定の構成を含む登録を作成できます.複数のネーミングクライアントを登録できます.各クライアントは事前に異なる設定を構成できます.この概念をより具体的にするために、例を見てみましょう.私のStartupでConfigureServicesメソッドでは、2つの追加パラメータを受け入れるAddHttpClientの異なるリロードメソッドを使用します.名前とアクションを「HttpClient」に依頼します.ConfigureServicesコード:
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("GitHubClient", client =>
    {
        client.BaseAddress = new Uri("https://api.github.com/");
        client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
        client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
    });

    services.AddMvc();
}
最初の文字列パラメータは、このクライアントの登録に使用される名前です.Actionの依頼により、HttpClientを構築するときに構成できます.これは、ベースアドレスと既知のリクエストヘッダを事前に定義できるため、非常に便利です.クライアントの名前付けを要求すると、新しいクライアントが作成され、そのたびにこの構成が適用されます.使用する場合、CreateClientは名前に基づいてクライアントを要求します.
[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;

    public ValuesController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    [HttpGet]
    public async Task Get()
    {
        var client = _httpClientFactory.CreateClient("GitHubClient");
        var result = await client.GetStringAsync("/");

        return Ok(result);
    }
}
この例では、作成したHttpClientインスタンスには基本アドレスセット(base address set)があるので、GetStringAsyncメソッドは対応するURIに転送すればよい.
このネーミング方式により、HttpClientに適用される構成を制御することができます.私は「魔力文字列」の忠実なファンではないので、名前付きクライアントを使用すると、クライアント名の文字列定数を含む静的クラスがあるかもしれません.このように:
public static class NamedHttpClients
{
    public const string GitHubClient = "GitHubClient";
}
クライアントを登録(またはリクエスト)する場合は、「魔力文字列」ではなく静的クラス値を使用できます.
services.AddHttpClient(NamedHttpClients.GitHubClient, client =>
{
    client.BaseAddress = new Uri("https://api.github.com/");
    client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
    client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
});
これは素晴らしいですが、カスタマイズされたタイプ化クライアントの使用方法をさらに見ることができます.

タイプ化クライアント(Type Clients)


タイプ化クライアントでは、コンストラクション関数を介してHttpClientに注入されるカスタムクラスを定義できます.これにより、IHttpClientBuilderの拡張メソッドを使用してDIシステムをリンクしたり、汎用AddHttpClientメソッドを使用してカスタムタイプを受信したりすることができます.カスタムクラスがあれば、HttpClientを直接公開したり、Http callsを特定の方法にカプセル化したりして、外部サービスの使用をよりよく定義することができます.この方法は、「マジック文字列」を必要とせず、より合理的に見えることを意味します.カスタムタイプ化クライアントの基本例を見てみましょう.
public class MyGitHubClient
{
    public MyGitHubClient(HttpClient client)
    {
        Client = client;
    }

    public HttpClient Client { get; }
}
このクラスは構築関数でパラメータとしてのHttpClientを受け入れる必要がある.HttpClientのインスタンスに共通のプロパティを設定しました.次に、ConfigureServicesに登録する必要があります.
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient(client =>
    {
        client.BaseAddress = new Uri("https://api.github.com/");
        client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
        client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
    });

    services.AddMvc();
}
MyGitHubClientを汎用パラメータとしてAddHttpClientに渡した.DIシステムにtransient scopeとして登録されています.カスタムクラスはHttpClientを受け入れるため、関連するファクトリは適切な構成のHttpClientインスタンスを作成し、それを注入します.IHttpClientFactoryの代わりにコントローラを更新できるようになりました.
[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly MyGitHubClient _gitHubClient;

    public ValuesController(MyGitHubClient gitGitHubClient)
    {
        _gitHubClient = gitGitHubClient;
    }

    [HttpGet]
    public async Task Get()
    {
        var result = await _gitHubClient.Client.GetStringAsync("/");
        return Ok(result);
    }
}
カスタマイズされたタイプ化クライアントは、属性によってHttpClientを公開しているので、HTTP呼び出しに直接使用できます.

パッケージHttpClient(Encapsulating the HttpClient)


最後の例は、HttpClientを完全にカプセル化したい場合です.エンドポイントに対する特定の呼び出しを処理する方法を定義する場合、この方法が最も使用される可能性があります.このとき,応答と逆シーケンス化の検証を各方法でカプセル化し,単一の位置で処理することもできる.
public interface IMyGitHubClient
{
    Task<int> GetRootDataLength();
}

public class MyGitHubClient : IMyGitHubClient
{
    private readonly HttpClient _client;

    public MyGitHubClient(HttpClient client)
    {
        _client = client;
    }

    public async Task<int> GetRootDataLength()
    {
        var data = await _client.GetStringAsync("/");
        return data.Length;
    }
}
この場合,private readonlyフィールドを介して構造に注入されたHttpClientを格納した.このような(class)によって直接HttpClientを取得するのとは異なり、Http呼び出しを実行して要求長を返すGetRootDataLengthメソッドを提供します.簡単な例ですが、あなたはもう知っているはずです.次に示すように、コントローラを更新してインタフェースを受け入れ、使用できます.
[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly IMyGitHubClient _gitHubClient;

    public ValuesController(IMyGitHubClient gitHubClient)
    {
        _gitHubClient = gitHubClient;
    }

    [HttpGet]
    public async Task Get()
    {
        var result = await _gitHubClient.GetRootDataLength();
        return Ok(result);
    }
}
HttpClientと直接対話することなく、インタフェースで定義されたGetRootDataLengthメソッドを呼び出すことができます.これはテストに非常に役立ち、このコントローラをテストしたいときにIMyGitHubClientを簡単にシミュレートすることができます.過去にHttpClientをテストするのは少し苦しくて、私がいつも慣れている方法でもっとコードがあります.DIコンテナに登録すると、ConfigureServicesは次のようになります.
services.AddHttpClient(client =>
{
    client.BaseAddress = new Uri("https://api.github.com/");
    client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
    client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactoryTesting");
});
AddHttpClientには、DIの署名に対応する2つの汎用パラメータを受け入れる署名があります.

まとめ


この論文では、特定のネーミング構成を使用して異なるHttpClientインスタンスを作成することができるHttpClientFactoryのより高度な方法について検討します.次に,タイプ化クライアントを用いて,HttpClientインスタンスを受け入れる独自のクラスを拡張することによって実現することを議論した.HttpClientを直接公開したり、呼び出しをこのようなものにカプセル化してリモート・エンド・ポイントにアクセスしたりすることができます.次の記事では、DelegatingHandlersを使用して「送信要求ミドルウェア」(outgoing request middleware)を実現する別のモードについて説明します.