Как получить файлы cookie от HttpClientHandler.CookieContainer при использовании самостоятельного хостинга веб-API?

Я пытаюсь написать интеграционный тест для метода веб-API, который возвращает файл cookie. Основываясь на этом вопросе, я считаю, что мне нужно установить CookieContainer для HttpClientHandler.

HttpClient не сохраняет файлы cookie

Затем, исходя из этого вопроса, я думаю, мне нужно установить этот HttpClientHandler в качестве InnerHandler для моего экземпляра HttpServer, чтобы я мог связать обработчики.

Как выполнить тест HttpClientHandler в памяти

Проблема в том, что я все еще обнаруживаю, что CookieContainer пуст. У меня есть утверждение, которое проверяет наличие заголовка в ответе, который включает ожидаемый файл cookie. Вот мой код:

        // Set up in-memory hosting of Web API
        var config = new HttpConfiguration();
        WebApiConfig.Register(config);

        var cookieJar = new CookieContainer();
        var httpClientHandler = new HttpClientHandler
        {
            CookieContainer = cookieJar,
            UseCookies = true                
        };
        var httpServer = new HttpServer(config)
        {
            InnerHandler = httpClientHandler
        };

        const string loginUrl = "http://localhost/api/authentication/login";
        var uri = new Uri(loginUrl);

        var client = new HttpClient(httpServer) { BaseAddress = uri };

        var response =
            client.PostAsJsonAsync(uri,
                new LoginMessage {Email = UserEmail, Password = Password},
                CancellationToken.None).Result;
        response.EnsureSuccessStatusCode();

        var data = response.Content.ReadAsAsync<LoginResponse>().Result;
        Assert.IsTrue(response.Headers.Contains("Set-Cookie"));
        Assert.AreNotEqual(0, httpClientHandler.CookieContainer.Count);

Последнее утверждение о количестве элементов в CookieContainer не работает. Я также попытался вызвать httpClientHandler.CookieContainer.GetCookies(uri), но полученная коллекция файлов cookie по-прежнему содержит ноль элементов.

Я также попытался явно связать свои клиентские обработчики, но не заметил разницы в поведении.

        var cookieJar = new CookieContainer();
        var httpClientHandler = new HttpClientHandler
        {
            CookieContainer = cookieJar,
            UseCookies = true
        };
        var httpServer = new HttpServer(config);

        var client = HttpClientFactory.Create(httpClientHandler, httpServer);

Может ли кто-нибудь сказать мне, что я делаю неправильно, пытаясь получить эти файлы cookie? Файл cookie, который я вижу в заголовке ответа, выглядит так:

Temp=E4C4947BAB708D089C636B4A5BDA094A10C8B1D66347EBD96629CB9BDB589822198A09BCBBE22C13D07AFC4D4C3C91E78C08BECFC9CC03BEE881858A1B4752EDC1BB1E604B819FBAFE34776B6F46B78ADCD2421F8125A395784981BFF22CEBE19DB228158E85B5786279E55D4114B72E50098B2374C23A43B7C89EBA30F771C54E1D98A6B1CD315D1FB8623E8E97E41FE4279479B49D0A948E2752CA09BD17FF7B52764E96EA43DB9E98D7CEBD8A73C9547A696C170CFC9B6F75CA23B881ED9675C2344A2A16BEF2DFD70DBA723FB62578E7779ECADCF11347B22199DAC8FA6A; expires=Thu, 22 May 2014 01:37:36 GMT; path=/

person Bernard Chen    schedule 22.05.2014    source источник
comment
Если вы посмотрите на принятый ответ на вопрос, который вы связали, вы увидите, что для цепочки обработчиков вам необходимо установить HttpServer на внутренний обработчик. HttpClientHandler не является делегирующим обработчиком, поэтому связать его в цепочку будет невозможно. Я думаю, вам просто нужно проверить заголовок, а не пытаться использовать CookieJar.   -  person Darrel Miller    schedule 22.05.2014
comment
@DarrelMiller Спасибо, что разъяснили это. Мне было непонятно, какой из них должен быть внутренним обработчиком, хотя я заметил, что HttpClientHandler не был делегирующим обработчиком. Есть ли реализация делегирующего обработчика, который может обрабатывать файлы cookie, или вы можете указать мне на ресурс, который может помочь мне реализовать его?   -  person Bernard Chen    schedule 22.05.2014


Ответы (1)


На основании комментария, полученного мной по исходному вопросу от Даррела Миллера, похоже, что единственный способ справиться с этим - это если у нас есть делегирующий обработчик, который использует HttpServer в качестве внутреннего обработчика.

В итоге я создал свой собственный CookieDelegateHandler, который выглядит так:

    public class CookieDelegateHandler : DelegatingHandler
    {
        public CookieContainer CookieContainer { get; set; }
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return
                base.SendAsync(request, cancellationToken).ContinueWith(responseToCompleteTask
                    =>
                {
                    var result = responseToCompleteTask.Result;
                    var cookieHeaders = result.Headers.Where(pair => pair.Key == "Set-Cookie");
                    foreach (var value in cookieHeaders.SelectMany(header => header.Value))
                    {
                        CookieContainer.SetCookies(request.RequestUri, value);
                    }
                    return result;
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
        }
    }

С помощью этой реализации я могу создать экземпляр HttpClient следующим образом:

    var client = new HttpClient(new CookieDelegateHandler
    {
        CookieContainer = new CookieContainer(),
        InnerHandler = new HttpServer(config)
    });

Продолжение делегирующего обработчика выполняется, и файлы cookie добавляются в CookieContainer.

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

person Bernard Chen    schedule 22.05.2014
comment
Наличие этого типа функций в виде отдельных делегирующих обработчиков - лучший вариант в долгосрочной перспективе. Когда мы начнем переходить на HTTP / 2, мы больше не сможем использовать HttpClientHandler, и чем меньше вещей нужно будет повторно реализовать, тем лучше. То же самое и с переадресацией. Где-то есть вопрос о SO, где я реализовал свой собственный обработчик перенаправления. И декомпрессия, и кеширование. - person Darrel Miller; 22.05.2014