Как я могу отправить файл cookie из метода контроллера Web.Api

У меня есть служба Web.Api, в которой есть метод, который принимает пользовательский класс и возвращает другой пользовательский класс:

public class TestController : ApiController
{
    public CustomResponse Post([FromBody]CustomRequest request)
    {
        // process request
        ...
        // create response
        CustomResponse resp = new CustomResponse() { ... };
        return resp;
    }
}

Теперь я хочу также отправить файл cookie обратно как часть ответа Http. Как я могу это сделать?


person user1429080    schedule 31.05.2013    source источник


Ответы (3)


Мне удалось сделать это, объединив информацию из нескольких разных мест. Во-первых, чтобы иметь возможность легко отправлять файлы cookie в ответ, контроллер Web.Api должен возвращать экземпляр класса System.Net.Http.HttpResponseMessage (ссылка):

public class TestController : ApiController
{
    public HttpResponseMessage Post([FromBody]CustomRequest request)
    {
        var resp = new HttpResponseMessage();
        ...

        //create and set cookie in response
        var cookie = new CookieHeaderValue("customCookie", "cookieVal");
        cookie.Expires = DateTimeOffset.Now.AddDays(1);
        cookie.Domain = Request.RequestUri.Host;
        cookie.Path = "/";
        resp.Headers.AddCookies(new CookieHeaderValue[] { cookie });

        return resp;
    }
}

Но тогда как мне убедиться, что я могу ТАКЖЕ легко отправить обратно CustomResponse?

Хитрость заключается в ответе на этот вопрос. Используйте метод Request.CreateResponse<T> для объекта запроса. Тогда вся сделка становится:

public class TestController : ApiController
{
    public HttpResponseMessage Post([FromBody]CustomRequest request)
    {
        // process request
        ...

        var resp = Request.CreateResponse<CustomResponse>(
            HttpStatusCode.OK,
            new CustomResponse() { ... }
        );

        //create and set cookie in response
        var cookie = new CookieHeaderValue("customCookie", "cookieVal");
        cookie.Expires = DateTimeOffset.Now.AddDays(1);
        cookie.Domain = Request.RequestUri.Host;
        cookie.Path = "/";
        resp.Headers.AddCookies(new CookieHeaderValue[] { cookie });

        return resp;
    }
}
person user1429080    schedule 31.05.2013
comment
Это выглядит правильно. Если вы делаете это во многих методах действий, вы можете поместить это в фильтр действий. - person Mike Wasson; 31.05.2013
comment
Я был в восторге от этого замечательного веб-API, пока не увидел это. Какой позор, вы не можете просто добавить файл cookie, не возвращая HttpResponseMessage. Я думал, что идея состоит в том, чтобы сделать Web API проще, чем WCF. Боюсь, я этого не вижу. Как фильтр действий может помочь здесь, не усложняя такое простое требование. Не понимаю. - person ianbeks; 17.10.2013
comment
Извините, если я могу спросить, я немного смущен. Нужно ли мне захватить cookie ответа в клиенте и установить его, или браузер, который получает заголовок ответа set-cookie, должен делать это автоматически? - person Francis Ducharme; 07.08.2014
comment
@FrancisDucharme Если ваш клиент является браузером (возможно, вы используете Ajax для извлечения данных), тогда браузер должен обрабатывать файл cookie за вас. Если вашим клиентом является программа Windows (или аналогичная), вам возможно придется написать код для обработки файлов cookie самостоятельно. Я предлагаю вам опубликовать новый вопрос с подробностями вашей конкретной ситуации... - person user1429080; 08.08.2014

С последними версиями Web API, async и IHttpActionResult теперь мы можем просто сделать это:

public async Task<IHttpActionResult> MyMethod(... myParameters ...)
{
    ...
    var cookie = new CookieHeaderValue("myCookie", "myValue");
    ...

    var resp = new HttpResponseMessage();
    resp.StatusCode = HttpStatusCode.OK;
    resp.Headers.AddCookies(new[] { cookie });
    return ResponseMessage(resp);
}
person Simon Mourier    schedule 09.08.2018

На основе этот пост, WebApi получает заголовки, строку запроса и значения cookie и этот пост, api net mvc реализации файлов cookie, я использую следующие коды для получения и установки файлов cookie в разделе asp.net web api. Это работает, когда сервер находится на IIS Express, он должен работать и на сервере IIS. Но я не знаю, работает это или нет для самостоятельного размещения web-api.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;

namespace System.Web.Http
{

    /// <summary>
    /// Extends the HttpRequestMessage collection
    /// </summary>
    public static class HttpRequestMessageExtensions
    {
        /// <summary>
        /// Returns a dictionary of QueryStrings that's easier to work with 
        /// than GetQueryNameValuePairs KevValuePairs collection.
        /// 
        /// If you need to pull a few single values use GetQueryString instead.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static Dictionary<string, string> GetQueryStrings(this HttpRequestMessage request)
        {
            return request.GetQueryNameValuePairs()
                          .ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase);
        }

        /// <summary>
        /// Returns an individual querystring value
        /// </summary>
        /// <param name="request"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetQueryString(this HttpRequestMessage request, string key)
        {
            // IEnumerable<KeyValuePair<string,string>> - right!
            var queryStrings = request.GetQueryNameValuePairs();
            if (queryStrings == null)
                return null;

            var match = queryStrings.FirstOrDefault(kv => string.Compare(kv.Key, key, true) == 0);
            if (string.IsNullOrEmpty(match.Value))
                return null;

            return match.Value;
        }

        /// <summary>
        /// Returns an individual HTTP Header value
        /// </summary>
        /// <param name="request"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetHeader(this HttpRequestMessage request, string key)
        {
            IEnumerable<string> keys = null;
            if (!request.Headers.TryGetValues(key, out keys))
                return null;

            return keys.First();
        }

        /// <summary>
        /// Retrieves an individual cookie from the cookies collection
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cookieName"></param>
        /// <returns></returns>
        public static string GetCookie(this HttpRequestMessage request, string cookieName)
        {
            CookieHeaderValue cookie = request.Headers.GetCookies(cookieName).FirstOrDefault();
            if (cookie != null)
                return cookie[cookieName].Value;

            return null;
        }

        public static void SetCookie(this ApiController controller, string cookieName, string cookieValue)
        {
            HttpCookie cookie = new HttpCookie(cookieName, cookieValue);
            HttpContext.Current.Response.Cookies.Add(cookie); 
        }
    }
}
person AechoLiu    schedule 13.08.2013