C# 如何从Web.Api控制器方法发送cookie

C# 如何从Web.Api控制器方法发送cookie,c#,cookies,asp.net-web-api,C#,Cookies,Asp.net Web Api,我有一个Web.Api服务,它有一个接受自定义类并返回另一个自定义类的方法: public class TestController : ApiController { public CustomResponse Post([FromBody]CustomRequest request) { // process request ... // create response CustomResponse resp =

我有一个Web.Api服务,它有一个接受自定义类并返回另一个自定义类的方法:

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

现在,我还想将cookie作为Http响应的一部分发送回去。我怎样才能做到这一点呢?

我通过合并来自几个不同位置的信息来做到这一点。首先,为了能够轻松地在响应中发送cookie,Web.Api控制器应该返回
System.Net.Http.HttpResponseMessage
类()的实例:

但是,我如何确保我也可以轻松地发回
CustomResponse

诀窍就在于如何做到这一点。对请求对象使用
Request.CreateResponse
方法。整个交易将变成:

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;
    }
}
公共类TestController:ApiController
{
公共HttpResponseMessagePost([FromBody]CustomRequest)
{
//处理请求
...
var resp=Request.CreateResponse(
HttpStatusCode.OK,
新建CustomResponse(){…}
);
//创建并设置cookie作为响应
var cookie=新的CookieHeaderValue(“customCookie”、“cookieVal”);
cookie.Expires=DateTimeOffset.Now.AddDays(1);
cookie.Domain=Request.RequestUri.Host;
cookie.Path=“/”;
resp.Headers.AddCookies(新CookieHeaderValue[]{cookie});
返回响应;
}
}
基于和,我使用以下代码在
asp.net web api
下获取和设置cookie。当服务器在IIS Express上时,它可以工作;当服务器在IIS上时,它也应该工作。但我不知道它是否适用于自助主机
webapi

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); 
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用System.Net.Http;
使用System.Net.Http.Header;
使用System.Web;
命名空间System.Web.Http
{
/// 
///扩展HttpRequestMessage集合
/// 
公共静态类HttpRequestMessageExtensions
{
/// 
///返回更易于使用的查询字符串字典
///而不是GetQueryNameValuePairs KevValuePairs集合。
/// 
///如果需要提取几个单个值,请改用GetQueryString。
/// 
/// 
/// 
公共静态字典GetQueryString(此HttpRequestMessage请求)
{
返回请求。GetQueryNameValuePairs()
.ToDictionary(kv=>kv.Key,kv=>kv.Value,StringComparer.OrdinalIgnoreCase);
}
/// 
///返回单个querystring值
/// 
/// 
/// 
/// 
公共静态字符串GetQueryString(此HttpRequestMessage请求,字符串键)
{
//是的!
var queryStrings=request.GetQueryNameValuePairs();
if(querystring==null)
返回null;
var match=querystring.FirstOrDefault(kv=>string.Compare(kv.Key,Key,true)==0);
if(string.IsNullOrEmpty(match.Value))
返回null;
返回match.Value;
}
/// 
///返回单个HTTP头值
/// 
/// 
/// 
/// 
公共静态字符串GetHeader(此HttpRequestMessage请求,字符串键)
{
IEnumerable keys=null;
if(!request.Headers.TryGetValues(key,out key))
返回null;
返回键。First();
}
/// 
///从cookies集合中检索单个cookie
/// 
/// 
/// 
/// 
公共静态字符串GetCookie(此HttpRequestMessage请求,字符串cookieName)
{
CookieHeaderValue cookie=request.Headers.GetCookies(cookieName.FirstOrDefault();
if(cookie!=null)
返回cookie[cookieName]。值;
返回null;
}
公共静态void SetCookie(此ApiController控制器、字符串cookieName、字符串cookieValue)
{
HttpCookie cookie=新的HttpCookie(cookieName,cookieValue);
HttpContext.Current.Response.Cookies.Add(cookie);
}
}
}

通过最新版本的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);
}
公共异步任务MyMethod(…myParameters…)
{
...
var cookie=新CookieHeaderValue(“myCookie”、“myValue”);
...
var resp=新的HttpResponseMessage();
resp.StatusCode=HttpStatusCode.OK;
resp.Headers.AddCookies(新[]{cookie});
返回响应消息(resp);
}

看起来不错。如果你在很多动作方法中都这么做,你可以把它放到一个动作过滤器中。在我看到这个之前,我一直在说“哇,这个web api太棒了”。你不能只添加一个cookie而不返回HttpResponseMessage,这真是太遗憾了。我认为这个想法是为了使Web API比WCF更容易。恐怕我看不出来。一个动作过滤器如何在不增加如此简单需求的复杂性的情况下提供帮助。不明白。对不起,如果我可以问的话,我有点困惑。我是否需要在客户端抓取响应cookie并进行设置,或者获取设置cookie响应头的浏览器应该自动执行此操作?@FrancisDucharme如果您的客户端是浏览器(可能您正在使用Ajax获取数据),那么浏览器应该为您处理cookie。如果您的客户端是Windows程序(或类似程序),那么您可能需要自己编写一些cookie处理代码。我建议你发布一个新问题,详细说明你的具体情况。。。
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);
}