我需要使用HttpClientFactory
连接到外部api。
Startup.cs
中的代码看起来像这样
public void SetUpHttpClients(IServiceCollection services)
{
var loginEndpoint = Path.Combine(baseApi, "api/authentication);
var fileExists = File.Exists(certificatePath);
if (!fileExists)
throw new ArgumentException(certificatePath);
var certificate = new X509Certificate2(certificatePath, certPwd);
services.AddHttpClient("TestClient", client =>
{
client.BaseAddress = new Uri(baseApi);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
client.DefaultRequestHeaders.Add("ApiKey", apiKey);
var body = new { Username = username, Password = password };
var jsonBody = JsonConvert.SerializeObject(body);
var content = new StringContent(jsonBody, Encoding.UTF8, contentType);
var loginResponse = client.PostAsync(loginEndpoint, content).Result;
}).ConfigurePrimaryHttpMessageHandler(() =>
{
var cookieContainer = new CookieContainer();
var handler = new HttpClientHandler
{
CookieContainer = cookieContainer
};
handler.ClientCertificates.Add(certificate);
return handler;
});
我已使用HttpClientFactory将此代码添加到MessageController中,
public class MessagesController : Controller
{
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public IActionResult GetMessages()
{
var client = _httpClientFactory.CreateClient("TestClient");
var result = client.GetStringAsync("/api/messages");
return Ok(result);
}
}
但是当我尝试连接并从HttpClientFactory
获取消息时,出现此错误:
无法加载资源:net :: ERR_CONNECTION_RESET,404-BadRequest
答案 0 :(得分:2)
您试图在完成出厂配置之前发出请求,因为您在尝试配置客户端的同时仍在尝试使用该客户端,因此该帖子会失败。
这里的假设是在SetUpHttpClients
中正在调用ConfigureServices
。
public void ConfigureServices(IServiceCollection services) {
//...
SetUpHttpClients(services);
//...
services.AddMvc();
}
public void SetUpHttpClients(IServiceCollection services) {
var basePath = Directory.GetCurrentDirectory();
var certificatePath = Path.Combine(basePath, certPath);
var fileExists = File.Exists(certificatePath);
if (!fileExists)
throw new ArgumentException(certificatePath);
var certificate = new X509Certificate2(certificatePath, certPwd);
//Adding a named client
services.AddHttpClient("TestClient", client => {
client.BaseAddress = new Uri(baseApi);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
client.DefaultRequestHeaders.Add("ApiKey", apiKey);
})
.ConfigurePrimaryHttpMessageHandler(() => {
var cookieContainer = new CookieContainer();
var handler = new HttpClientHandler {
CookieContainer = cookieContainer
};
handler.ClientCertificates.Add(certificate);
return handler;
});
}
完成配置后,工厂可根据需要注入到控制器或服务类中。
以下示例显示了使用工厂作为控制器的依赖项。
[Route("api/[controller]")]
public class ValuesController : Controller {
private readonly IHttpClientFactory factory;
public MyController(IHttpClientFactory factory) {
this.factory = factory;
}
[HttpGet]
public async Task<IActionResult> Get() {
var client = factory.CreateClient("TestClient");
var result = client.GetStringAsync("api/messages");
return Ok(result);
}
}
在上面,工厂用于创建命名客户端的实例。它将具有在启动过程中设置的所有配置,其中包括带有证书的客户端处理程序。
要能够在启动过程中使用客户端(我建议不要这样做),首先需要将服务集合构建到服务提供程序中。
var serviceProvider = services.BuildServiceProvider();
var factory = serviceProvider.GetService<IHttpClientFactory>();
var client = factory.CreateClient("TestClient");
var body = new { Username = username, Password = password };
var jsonBody = JsonConvert.SerializeObject(body);
var content = new StringContent(jsonBody, Encoding.UTF8, contentType);
var loginResponse = client.PostAsync("api/authentication", content).Result;
//...do something with the response
但是,这可能会带来无法预料的结果,因为在启动过程的这一阶段,服务集合还没有完全填充。
答案 1 :(得分:1)
我已经解决了这个问题。 SetUpHttpClient
方法如下:
public void SetUpHttpClients(IServiceCollection services)
{
var basePath = Directory.GetCurrentDirectory();
var certificatePath = Path.Combine(basePath, CertPath);
var fileExists = File.Exists(certificatePath);
if (!fileExists)
throw new ArgumentException(certificatePath);
var certificate = new X509Certificate2(certificatePath, CertPwd);
services.AddHttpClient("TestClient", client =>
{
client.BaseAddress = new Uri(BaseApi);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Accept));
client.DefaultRequestHeaders.Add("ApiKey", ApiKey);
}).ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
return handler;
});
}
我已添加到服务并从控制器调用的登录和消息的其余代码。
MessageClient.cs
public MessageClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
_client = _httpClientFactory.CreateClient("TestClient");
var body = new { UserName = Username, UserPassword = Password };
var jsonBody = JsonConvert.SerializeObject(body);
var content = new StringContent(jsonBody, Encoding.UTF8, ContentType);
var loginEndpoint = Path.Combine(BaseApi, "api/authentication");
_responseMessage = _client.PostAsync(loginEndpoint, content).Result;
}
public async Task<string> ReadMessages()
{
try
{
string messages = "";
if (_responseMessage.IsSuccessStatusCode)
{
var messagesEndpoint = Path.Combine(BaseApi, "api/messages/");
var cookieContainer = new CookieContainer();
var handler = new HttpClientHandler { CookieContainer = cookieContainer };
var cookiesToSet = GetCookiesToSet(_responseMessage.Headers, BaseApi);
foreach (var cookie in cookiesToSet)
{
handler.CookieContainer.Add(cookie);
}
var messageResponse = await _client.GetAsync(messagesEndpoint);
messages = await messageResponse.Content.ReadAsStringAsync();
}
return messages;
}
catch (Exception e)
{
throw e.InnerException;
}
}
MessageContoller.cs
[HttpGet]
public async Task<ActionResult> GetMessages()
{
var result = await _messageClient.ReadMessages();
return Ok(result);
}
感谢@Nkosi。