在dotnet core中具有相同实现的多个httpclient实例

时间:2020-08-10 04:40:03

标签: c# asp.net-core httpclient

我想调用第三方API,该API为我们提供了两个不同的授权令牌值。因此,通过调用相同的端点URL,我们可以得到两组不同的结果。

EndpointUrl: https://mail.yahoo.com/ 
Authorization: Token User123
//Do something with the response for User123
Authorization: Token User345
//Do something with the response for User345

在我的客户服务中,包装函数应通过使用不同的令牌值两次调用此API来调用此API。获取结果并将其合并。

这是我的服务。

public class MailService : IMailService
{
    private readonly HttpClient _httpClient;
    
    public MailService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<UserResponse> GetUserResponse()
    {
        var uri = new Uri(_httpClient.BaseAddress.AbsoluteUri + "/user-data/");
        var response = await _httpClient.GetAsync(uri);
        return response;
    }
}

我正在使用Typed Client

services.AddHttpClient<IMailService,MailService>(client =>
{
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", "User123");                
    client.BaseAddress = new Uri("https://mail.yahoo.com/");
})

问题陈述:

检索结果的最佳方法是什么?我不确定是否应该创建HttpClient的两个单独实例?如果要使用两个包含自己的HttpClient的不同类,则要避免重复代码。

也许我的解决方案位于Named Client中。我只是不知道如何优雅地实现它。

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

我要回答,这或多或少是基于意见的。我希望将DI服务与项目中的其他所有服务分离。基本上,您是在startup.cs中将配置放入另一个服务。我喜欢将所有这些东西都保留在使用HttpClient的服务中。

因此,当我注入IHttpClientFactory时,我可以通过简单地调用:

services.AddHttpClient();

继续前进。

现在,在您的MailService中,您应这样注入它:

public class MailService : IMailService
{
    // or store this in your applications external configuration
    const Uri BaseUri = new Uri("https://mail.yahoo.com/");
    const string UserDataPath = "/user-data/";
    
    private readonly IHttpClientFactory _httpClientFactory;
    
    public MailService(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public async Task<UserResponse> GetUserResponse(string token)
    {
        var client = _httpClientFactory.CreateClient();
        
        var uri = new UriBuilder(BaseUri){ Path = UserDataPath }.Uri;
        
        using (var msg = new HttpRequestMessage(HttpMethod.Get, uri))
        {
            msg.Headers.Authorization = new AuthenticationHeaderValue("Token", token); 
            using (var resp = await _client.SendAsync(msg).ConfigureAwait(false))
            {
                resp.EnsureSuccessStatusCode();
                return await resp.Content.ReadAsAsync<UserResponse>().ConfigureAwait(false);
            }
        }
    }
}

请记住,您应该使用HttpRequestMessage模式,而不要修改Default...的任何HttpClient属性。那时,它可能正在应用程序中的其他地方使用。

使用HttpRequestMessage可确保您获得一组新的标头,其他人都无法修改。总结一下:HttpClient.Headers are not thread-safe

ETA:

现在我考虑一下...这确实是您的问题。您想使用一个HttpClient使用两个不同的标题。在您介绍的场景中将无法使用。您将必须拥有两个HttpClient,它们具有各自不同的标题。

因此,如果您不想采用我介绍的老式方法,则应考虑“命名”客户端...每个配置都有不同的名称。

答案 1 :(得分:0)

检索结果的最佳方法是什么?

命名客户端是一种解决方案,如果确定您将始终具有两个身份验证标头。不过,这对我来说似乎很奇怪。

SendAsync是另一种解决方案。通过调用SendAsync而不是GetAsync,可以提供可以包含自定义标头的HttpRequestMessage。为了方便起见,GetAsync实际上是SendAsync的包装,并且您可以使用较低级别的SendAsync,因为需要更多的自定义功能。

相关问题