Asp.net core 在.NET Core 2中注册基于作用域的HttpClient
我有NetCore2WebAPI应用程序。在这个过程中,我必须调用客户端A的API来获取一些数据。所以我使用HttpClient来调用它。客户端A还要求我在头中传递用户ID和密码 因此,与直接注入Asp.net core 在.NET Core 2中注册基于作用域的HttpClient,asp.net-core,.net-core,asp.net-core-2.0,asp.net-core-webapi,coreclr,Asp.net Core,.net Core,Asp.net Core 2.0,Asp.net Core Webapi,Coreclr,我有NetCore2WebAPI应用程序。在这个过程中,我必须调用客户端A的API来获取一些数据。所以我使用HttpClient来调用它。客户端A还要求我在头中传递用户ID和密码 因此,与直接注入HttpClient不同,我使用了HttpClient包装器,如下所示 public class ClientA : IClientA { private readonly HttpClient _httpClient; public ClientA(HttpClient httpCl
HttpClient
不同,我使用了HttpClient
包装器,如下所示
public class ClientA : IClientA
{
private readonly HttpClient _httpClient;
public ClientA(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<string> GetData()
{
return await _httpClient.HttpGetAsync("someurl");
}
}
然后我在Startup.cs中注册所有内容
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyService, MyService>();
services.AddScoped(factory =>
{
Func<Task<IClientA>> provider = async () =>
{
using (var dbContext = factory.GetService<MyDBContext>())
{
// get userid and password from database here
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("UserId",userid);
httpClient.DefaultRequestHeaders.Add("Password",password);
return new ClientA(httpClient);
}
};
return provider;
});
}
解决了我的问题
services.AddScoped<IClientA>(factory =>
{
var dbContext = factory.GetService<MyDBContext>();
// get userid and password from database here
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("UserId",userid);
httpClient.DefaultRequestHeaders.Add("Password",password);
return new ClientA(httpClient);
});
services.AddScoped(工厂=>
{
var dbContext=factory.GetService();
//在此处从数据库获取用户ID和密码
var httpClient=新的httpClient();
httpClient.DefaultRequestHeaders.Add(“UserId”,UserId);
httpClient.DefaultRequestHeaders.Add(“密码”,Password);
返回新客户(httpClient);
});
您不希望在限定范围的上下文中实例化httpclient,即为每个请求创建httpclient实例,这不是该类的推荐使用模式。(不会很好地扩展)
根据您的设置,为每个客户创建一个单独的接口(假设有少量客户)-可能在其实现中有代码访问安全需求(启用身份模拟?)
这将a)扩展良好b)每个客户每个应用程序实例/启动只运行一次,c)强制执行访问检查以了解使用情况
此外,此答案与您的标题要求相关-该注册的某些内容看起来不对劲。您正在注册用于创建客户端的函数,而不是客户端本身。yeeeks@Nkosi你是对的。复制粘贴问题在我这边。没有必要注入HttpClient。这是一个实用类。您应该根据需要手动创建实例。如果有的话,请使用选项模式(例如,
IOptions
)注入HttpClient所需的参数。这不是相同的代码。最初的代码是重新调整函数的,而这段代码实际上返回了IClientAI。对于开发人员来说,这段代码比一大堆句子更具解释性:)我会记住这一点,因为这是一个范围注册,这段代码仍在为每个用户请求实例化http客户端,这意味着它在加载时会失败。(请参阅我答案中的链接)。这是一个严重的反模式,如果发生足够的负载,它将破坏应用程序的稳定性!如果您的应用程序处理的请求不多,它可能会起作用,但如果他们的应用程序处理的请求不止这些,则任何人都不应使用此解决方案。请不要创建所有类型的HttpClient,请使用IHttpClientFactory来创建。注册HttpClient的singleton实例可能可以,但如果您必须使用请求和响应Http头,然后,在每次请求/响应之后,您都必须不断清除Http头。否则,它们将在HttpClient进入后被缓存singlton@LP13您可以有一个单例,然后使用SendAsync方法处理一个请求,该请求专门处理所需的头(使头与单例分开/解耦)。例如:HttpRequestMessage请求=新建HttpRequestMessage(HttpMethod.Delete,url);request.Headers.Authorization=新的AuthenticationHeaderValue(“承载者”,UserSpecificAccessToken);HttpResponseMessage response=等待客户端.SendAsync(请求);(客户端是单例/静态HttpClient实例)
public class ClientB(HttpClient client)
{
private readonly _httpClient;
public class ClientB(HttpClient client)
{
_httpClient = client;
}
public string CallClientB(string url)
{
// here ClientB will receive ClientA's credentials
return await _httpClient.HttpGetAsync(url);
}
}
services.AddScoped<IClientA>(factory =>
{
var dbContext = factory.GetService<MyDBContext>();
// get userid and password from database here
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("UserId",userid);
httpClient.DefaultRequestHeaders.Add("Password",password);
return new ClientA(httpClient);
});