How do I convert the Cookies collection to a generic list? Easily
Asked Answered
C

5

12

Anyone know how I can convert Request.Cookies into a List<HttpCookie>? The following didn't work as it throws an exception.

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

Exception: Unable to cast object of type 'System.String' to type 'System.Web.HttpCookie'

Cranwell answered 27/5, 2010 at 16:5 Comment(0)
A
14

The reason this happens is because the NameObjectCollectionBase type that Request.Cookies derives from enumerates over the keys of the collection and not over the values. So when you enumerate over the Request.Cookies collection you are getting the keys:

public virtual IEnumerator GetEnumerator()
{
    return new NameObjectKeysEnumerator(this);
}

This means that the following will work:

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

I guess you could try the following which might be considered ugly but will work:

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

UPDATE:

As pointed out by @Jon Benedicto in the comments section and in his answer using the AllKeys property is more optimal as it saves a cast:

List<HttpCookie> lstCookies = Request.Cookies.AllKeys
    .Select(x => Request.Cookies[x]).ToList();
Atkins answered 27/5, 2010 at 16:20 Comment(5)
But then you lose the key -> value connection :)Goldia
@Snake, I agree with you that this is not optimal from performance standpoint as it will enumerate the collection multiple times but if you have a couple of elements it might not be dramatical.Atkins
Using the AllKeys member of HttpCookieCollection saves a cast. See my answer for code.Sonasonant
This helped me solve an issue with XmlSerializer serializing the keys and not the values. My NameObjectCollectionBase subclass needed to override GetEnumerator as return this.BaseGetValues().GetEnumerator();Adonai
Note when 2 cookies with the same key is received (a=1; a=2) Response.Cookies[string] always return the first one (a=1). Instead you need to use something like Request.Cookies.AllKeys.Select((_, x) => Request.Cookies[x])Virginity
S
6

If you really want a straight List<HttpCookie> with no key->value connection, then you can use Select in LINQ to do it:

var cookies = Request.Cookies.AllKeys.Select(x => Request.Cookies[x]).ToList();
Sonasonant answered 27/5, 2010 at 16:31 Comment(2)
IE can send multiple cookies with the same name if the cookies are created in separate domains. If this happens then the code above loses one of the cookies.Slick
The code gets only the first cookie with the same name.Fane
B
3

The question may be a bit old, but the answers here are not covering all cases, because as pointed out by @C.M. there can be multiple cookies with the same name.

So the easiest way is to loop the cookies collection with a for loop:

var existingCookies = new List<HttpCookie>();

for (var i = 0; i < _httpContext.Request.Cookies.Count; i++)
{
    existingCookies.Add(_httpContext.Request.Cookies[i]);
}
Bickford answered 22/5, 2014 at 10:45 Comment(0)
G
2

.Cookies.Cast<HttpCookie>(); tries to cast the collection of keys to a collection of cookies. So it's normal that you get an error :)

It's a name -> value collection, so casting to a list wouldn't be good.

I would try converting it to a dictionary.

For example:

Since Cookies inherits from NameObjectCollectionBase you can GetAllKeys(), and use that list to get all the values and put them in a Dictionary.

For example:

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

foreach(var key in Request.Cookies.GetAllKeys())
{
    cookieCollection.Add(key, Request.Cookies.Item[key]);
}
Goldia answered 27/5, 2010 at 16:10 Comment(0)
B
0

You can avoid iterating the keys by using the collection's Count with Enumerable.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));
  }
}
Bibbs answered 8/9, 2021 at 21:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.