ASP.NET Core 2.1 in HttpClientFactory (Part 2) defines the name and type of the client

Original: https: //www.stevejgordon.co.uk/httpclientfactory-named-typed-clients-aspnetcore  
Posted: January 2018

      Previous article "HttpClientFactory Introduction" I explained the reason for creating this feature. We know the problems it can solve, and then include a very basic example shows how to use it in WebAPI application. In this article, I would like to discuss the other two methods you can use it: name of the client (named clients) and the type of client (typed clients).

Name of the client (Name Clients)

      In the first article, I demonstrate how to use HttpClientFactory to obtain basic HttpClient instance. When you just from a single location to quickly send out a request, which is good. But in general, you may want to make multiple requests from multiple locations in the code to the same service.
      By naming concept of the client, HttpClientFactory make this easier. Use name of the client, you can create a registry, which contains some specific configuration when you create the HttpClient. You can register multiple names of clients, each client can be configured with different settings in advance.
      To make this concept more concrete, let's look at an example. In my Startup.ConfigureServices method, AddHttpClient different overloaded method accepts two additional parameters. Put a name and an Action delegate "told" HttpClient. ConfigureServices Code:

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();
}

      The first string parameter is the name of this client is registered. Action <HttpClient> commission allows us to configure them when we construct HttpClient. This is convenient, because we can define a pre-known number of base address and request header. When we requested name of the client, it will create a new client for us, and every time you apply this configuration.
      When used, CreateClient by name to request a client:

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;

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

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

        return Ok(result);
    }
}

      In this example, HttpClient instance we've created a basic set of addresses (base address set), so our GetStringAsync method can be passed in the corresponding URI.

      This naming of the way so that we can control is applied HttpClient configuration. I am not a "magic string" of loyal fans, so if I use named client, I might have a static class that contains the string constant client name. like this:

public static class NamedHttpClients
{
    public const string GitHubClient = "GitHubClient";
}

      Registration (or request) the client, we can use the static class values, rather than "magic string":

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");
});

      This is very good, but we can go further, take a look at how to use the type of client-defined.

Type of client (Typed Clients)

      The type of client allows us to define a custom class HttpClient injection via the constructor. We use the extension method IHttpClientBuilder link DI system, or use a generic method for receiving AddHttpClient custom type. Once we have a custom class, we can directly HttpClient disclosed, Http calls may also be encapsulated in a particular method so as to better define the use of external services. This approach also means that we no longer need to "magic string", and it seems more reasonable.
      Let's look at a basic example of the definition of the type of client from:

public class MyGitHubClient
{
    public MyGitHubClient(HttpClient client)
    {
        Client = client;
    }

    public HttpClient Client { get; }
}

      This class needs HttpClient accepts as a parameter in the constructor. Now, we have set up a public property for the HttpClient instance.
      Then, we need to register in ConfigureServices in:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient<MyGitHubClient>(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();
}

      We will MyGitHubClient passed as a parameter to the generic AddHttpClient. It was registered as a transient scope in the DI system. As our custom class HttpClient to accept, and therefore associated with "factory" creates an instance of HttpClient properly configured, and injected it. The controller can now be updated to accept our type of client instead IHttpClientFactory:

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly MyGitHubClient _gitHubClient;

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

    [HttpGet]
    public async Task<ActionResult> Get()
    {
        var result = await _gitHubClient.Client.GetStringAsync("/");
        return Ok(result);
    }
}

      Since our custom type of client discloses HttpClient through the property, so we can use it to direct HTTP calls.

封装HttpClient(Encapsulating the HttpClient)

      A final example is the situation we want to completely encapsulate the HttpClient. When we want to call a particular method of endpoint definition process, most likely to use this method. In this case, we can encapsulate response and deserialized in each authentication method in order to process it at a single location.

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;
    }
}

      In this case, we injected stored in the configuration HttpClient by private readonly field. And get (class) directly through such different HttpClient, we provide a way to perform Http GetRootDataLength call and returns the requested length. As a simple example, but you should already know!
      We can now update the controller to accept and use the interface, as shown below:

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly IMyGitHubClient _gitHubClient;

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

    [HttpGet]
    public async Task<ActionResult> Get()
    {
        var result = await _gitHubClient.GetRootDataLength();
        return Ok(result);
    }
}

      We can now call GetRootDataLength methods defined on the interface, without having to interact directly with the HttpClient. This is useful for testing, can now easily simulate IMyGitHubClient when we want to test the controller. The last test HttpClient a little pain, according to my usual habit of the way there will be more code.
      Registered in the DI container, ConfigureServices becomes:

services.AddHttpClient<IMyGitHubClient, MyGitHubClient>(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 has a signature accepting two generic parameters, corresponding to DI signature.

to sum up

      In this article, we explore the HttpClientFactory some more advanced method, which allows us to use a particular name to create a different configuration HttpClient instance. Then we discuss the use of the type of client, by extending achieve our own class, which accepts HttpClient instance. We can directly open HttpClient, can encapsulate calls to this class to access the remote endpoint.
      The next article, we will discuss the use DelegatingHandlers to achieve another mode "outgoing requests middleware" (outgoing request middleware) is.

 

Guess you like

Origin www.cnblogs.com/lookerblue/p/11120361.html