6

Is there a way to let TempData store in a browser's cookie instead of Session State. I have Session State disabled on my site.

Thanks.

4 Answers4

6

You can use brock Allen's Cookie TempData provider. Is fully documented here and it's also available as a NuGet package.

It takes into account, between other things, an important concern: security.

It's really easy to make MVC TempData use this package.

JotaBe
  • 38,030
  • 8
  • 98
  • 117
3

You can specify your own custom TempDataProvider and write it so that it stores in temp data.

Take a look at this blog post for an example where someone uses a custom tempdata provider

Matthew Manela
  • 16,572
  • 3
  • 64
  • 66
  • Please see my other thread http://stackoverflow.com/questions/3809379/asp-net-mvc-tempdata-in-browser-cookie –  Sep 29 '10 at 02:19
1

I use the following little class file:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web;
using System.Web.Mvc;

/* 16-09-2010
 * pulled from Microsoft.Web.Mvc Futures
 * be careful in case future versions of the mvc dll incorporate this
 * 
 */

namespace yournamespace
{
    public class CookieTempDataProvider : ITempDataProvider
    {
        internal const string TempDataCookieKey = "__ControllerTempData";
        readonly HttpContextBase _httpContext;

        public CookieTempDataProvider(HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }
            _httpContext = httpContext;
        }

        public HttpContextBase HttpContext
        {
            get
            {
                return _httpContext;
            }
        }

        protected virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
        {
            HttpCookie cookie = _httpContext.Request.Cookies[TempDataCookieKey];
            if (cookie != null && !string.IsNullOrEmpty(cookie.Value))
            {
                IDictionary<string, object> deserializedTempData = DeserializeTempData(cookie.Value);

                cookie.Expires = DateTime.MinValue;
                cookie.Value = string.Empty;

                if (_httpContext.Response != null && _httpContext.Response.Cookies != null)
                {
                    HttpCookie responseCookie = _httpContext.Response.Cookies[TempDataCookieKey];
                    if (responseCookie != null)
                    {
                        cookie.Expires = DateTime.MinValue;
                        cookie.Value = string.Empty;
                    }
                }

                return deserializedTempData;
            }

            return new Dictionary<string, object>();
        }

        protected virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
        {
            var cookieValue = SerializeToBase64EncodedString(values);

            var cookie = new HttpCookie(TempDataCookieKey)
                             {
                                 HttpOnly = true, Value = cookieValue
                             };

            _httpContext.Response.Cookies.Add(cookie);
        }

        public static IDictionary<string, object> DeserializeTempData(string base64EncodedSerializedTempData)
        {
            var bytes = Convert.FromBase64String(base64EncodedSerializedTempData);
            var memStream = new MemoryStream(bytes);
            var binFormatter = new BinaryFormatter();
            return binFormatter.Deserialize(memStream, null) as IDictionary<string, object>;
        }

        public static string SerializeToBase64EncodedString(IDictionary<string, object> values)
        {
            var memStream = new MemoryStream();
            memStream.Seek(0, SeekOrigin.Begin);
            var binFormatter = new BinaryFormatter();
            binFormatter.Serialize(memStream, values);
            memStream.Seek(0, SeekOrigin.Begin);
            var bytes = memStream.ToArray();
            return Convert.ToBase64String(bytes);
        }

        IDictionary<string, object> ITempDataProvider.LoadTempData(ControllerContext controllerContext)
        {
            return LoadTempData(controllerContext);
        }

        void ITempDataProvider.SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
        {
            SaveTempData(controllerContext, values);
        }
    }
}

and then add it to my contoller as such:

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        base.Initialize(requestContext);
        TempDataProvider = new CookieTempDataProvider(requestContext.HttpContext); 
    }

seems to work fine...

jim tollan
  • 22,305
  • 4
  • 49
  • 63
  • I have the same code which is taken from futures asssembly. Anyway, I would like to remove the cookie from Response, but it's not working for me. Can you check my other thread http://stackoverflow.com/questions/3809379/asp-net-mvc-tempdata-in-browser-cookie –  Sep 29 '10 at 02:20
  • Nazaf - i'll post below the method i use to remove cookies (not specific to tempdata but should work) – jim tollan Sep 29 '10 at 07:24
-1

Nazaf,

try this for removing your cookies:

public void DeleteCookie(string name)
{
    DateTime now = DateTime.UtcNow;
    string cookieKey = name;
    var cookie = new HttpCookie(cookieKey, null)
    {
        Expires = now.AddDays(-1)
    };
    HttpContext.Response.Cookies.Set(cookie);
}

usage:

DeleteCookie("__ControllerTempData");
jim tollan
  • 22,305
  • 4
  • 49
  • 63
  • It didn't work either. It seems that Response does not apply any modifications, they simply do not take effect. This must be a bug! Thanks anyway! –  Sep 30 '10 at 04:31
  • JotaBe, you are indeed correct regarding not mentioning TempData. It does however mitigate using session state which was of course another component of the question. btw - i appreciate you actually mentioning why you did the downvote, so many folk just do it anonymously - i respect that. cheers for now – jim tollan Jan 30 '14 at 11:23
  • @jimtollan: this is a good solution for a problem... but not for the problem in the question. So, it's a pity, but noone will find your solution. If you creata a question for this answer, and move this answer to that question, I'll vote for it (add a comment to let me know, if you do it). In this way, people with this problem will find your good solution (and probably vote for it). When a new problem arises from a question, it should be discussed in the comments, or in a new question, with a link in the comments. At least, that's what I humbly think. – JotaBe Jan 31 '14 at 11:52