HttpClientFactory BadRequest? - PullRequest
       47

HttpClientFactory BadRequest?

0 голосов
/ 24 июня 2018

Мне нужно использовать 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;
}); 

Я добавил этот код в MessageController с помощью HttpClientFactory,

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

Ответы [ 2 ]

0 голосов
/ 25 июня 2018

Я решил эту проблему.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.

0 голосов
/ 24 июня 2018

Вы пытаетесь сделать запрос перед завершением заводской конфигурации. Эта публикация завершится ошибкой, потому что вы пытаетесь использовать клиент, все еще настраивая его.

Здесь предполагается, что 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;
    });
}

После завершения настройки фабрика становится доступной для внедрения в контроллер или класс обслуживания по мере необходимости.

В следующем примере показано использование фабрики в качестве зависимости отcontroller.

[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

Однако это может привести к непредвиденным результатам, так как на этом этапе в процессе запуска коллекция услуг не была бы полностью заполнена.

...