如何将Cookies集合转换为通用列表?简单易行。

12

有人知道我如何将Request.Cookies转换为List<HttpCookie>吗?下面的代码没有起作用,因为它会抛出异常。

List<HttpCookie> lstCookies = new List<HttpCookie>(
    Request.Cookies.Cast<HttpCookie>());

异常:无法将类型为“System.String”的对象转换为类型“System.Web.HttpCookie”

5个回答

14
这种情况发生的原因是因为Request.Cookies继承自NameObjectCollectionBase类型,该类型枚举集合时枚举的是键而不是值。所以当您枚举Request.Cookies集合时,您获得的是键:
public virtual IEnumerator GetEnumerator()
{
    return new NameObjectKeysEnumerator(this);
}

这意味着以下内容将起作用:

string[] keys = Request.Cookies.Cast<string>().ToArray();

我猜你可以尝试以下方法,虽然可能比较丑陋,但是它会起作用:

List<HttpCookie> lstCookies = Request.Cookies.Keys.Cast<string>()
    .Select(x => Request.Cookies[x]).ToList();

更新:

正如在评论区和他的答案中@Jon Benedicto指出的那样,使用AllKeys属性更加优化,因为它避免了强制转换:

List<HttpCookie> lstCookies = Request.Cookies.AllKeys
    .Select(x => Request.Cookies[x]).ToList();

但是这样你就失去了键值连接 :) - Snake
@Snake,我同意你的观点,从性能角度来看,这并不是最优的方法,因为它会多次枚举集合,但如果你只有几个元素,那么影响可能不会太大。 - Darin Dimitrov
3
使用HttpCookieCollection的AllKeys成员可以避免强制转换。请参阅我的答案中的代码。 - Jon Benedicto
这帮助我解决了XmlSerializer序列化键而不是值的问题。我的NameObjectCollectionBase子类需要重写GetEnumerator,如下所示:return this.BaseGetValues().GetEnumerator(); - B2K

6
如果你真的想要一个没有键值对连接的直接的List<HttpCookie>,那么你可以使用LINQ中的Select来实现:
var cookies = Request.Cookies.AllKeys.Select(x => Request.Cookies[x]).ToList();

如果在不同的域中创建了具有相同名称的多个Cookie,则IE可以发送这些Cookie。如果发生这种情况,则上面的代码将失去其中一个Cookie。 - C.M.
代码仅获取具有相同名称的第一个 cookie。 - d.popov

3

这个问题可能有点老,但是这里的答案并没有涵盖所有情况,因为正如@C.M.指出的那样,可能存在多个同名的cookie。

所以最简单的方法是使用for循环遍历cookies集合:

var existingCookies = new List<HttpCookie>();

for (var i = 0; i < _httpContext.Request.Cookies.Count; i++)
{
    existingCookies.Add(_httpContext.Request.Cookies[i]);
}

2

.Cookies.Cast<HttpCookie>();尝试将键的集合转换为cookie的集合。所以你得到一个错误是正常的 :)

它是一个名称-值的集合,所以转换为列表不是很好。

我建议尝试将其转换为字典。

例如:

由于Cookies继承自NameObjectCollectionBase,因此您可以GetAllKeys(),并使用该列表获取所有值并将其放入字典中。

例如:

Dictionary cookieCollection = new Dictionary<string, object>();

foreach(var key in Request.Cookies.GetAllKeys())
{
    cookieCollection.Add(key, Request.Cookies.Item[key]);
}

0

您可以通过使用集合的 CountEnumerable.Range 来避免迭代键。

using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Foo
{
  public static class WebHttpExtensions
  {
    public static IEnumerable<HttpCookie> AsEnumerable(this HttpCookieCollection webCookies) =>
      Enumerable
        .Range(0, webCookies.Count)
        .Select(ndx => webCookies[ndx]);

    public static IEnumerable<System.Net.Cookie> ToNetCookies(this HttpCookieCollection webCookies) => 
      webCookies
        .AsEnumerable()
        .Select(x => new System.Net.Cookie(x.Name, x.Value));
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接