我有.NET Core 2 Web API应用程序。在此过程中,我必须调用客户端A的API来获取一些数据。所以我使用HttpClient来调用它。客户端A还要求我在标题中传递用户标识和密码。
所以我没有直接注入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");
}
}
然后在服务中使用ClientA
public class MyService :IMyService
{
private readonly IClientA _clientA
public MyService(IClientA clientA)
{
_clientA= clientA
}
public void DoSomethig()
{
_clientA.GetData();
}
}
然后我在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;
});
}
然而我收到错误
为简洁起见,System.InvalidOperationException:无法解析类型的服务 尝试激活时'System.Net.Http.HttpClient' 'XXXXXXXXX.ClientA'。在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(类型 serviceType,Type implementationType,ISet
1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet
1 callSiteChain)
删除了剩余的异常
请注意,在注册期间,我是HttpClient
的新实例并将其传递给ClientA类,因为我必须设置用户ID和密码。
为了消除上述错误,我可以使用DI框架注册带有UserID和密码的HttpClient,我猜这样可行。
但是,在这种情况下,如果有另一个客户端ClientB,它接受HttpClient,那么DI框架将注入具有用户ID和密码的相同httpclient。这将产生安全问题,因为ClientB会在请求标头中看到ClientA的凭据。
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);
}
}
答案 0 :(得分:3)
您不希望在作用域上下文中实例化httpclient,即为每个请求创建一个httpclient实例,这不是该类的推荐使用模式。 (不会很好地扩展)。 https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
为每个客户创建一个单独的接口(假设客户数量很少) - 可能在其实施中具有代码访问安全性需求,具体取决于您的设置(启用身份模拟?)
这将a)规模很好b)每个应用程序实例/启动每个客户只运行一次,c)强制执行访问检查。
此外,此答案已与您的标题要求相关联且相关 - HttpClient single instance with different authentication headers
答案 1 :(得分:-1)
解决了我的问题
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);
});