web 2.0

Session-less Controllers and TempData in ASP.NET MVC


Introduction

Microsoft has released ASP.NET MVC 3 RC with a dozen of exciting features. One of these features is Sessionless controllers, meaning you can specify the type of session state behavior that is required in order to support HTTP requests to a controller.

Sessionless Controller

If you are not using Session State in your web site, you can gain slight performance improvement by disabling session state globally. However, if you use session state in some controllers, you can keep it in those controllers, and disable it in those that are not using it.

The new ControllerSessionStateAttribute gives you more control over session-state behavior for controllers by specifying a System.Web.SessionState.SessionStateBehavior enumeration value. The following example shows how to turn off session state for all requests to a controller.

[ControllerSessionState(SessionStateBehavior.Disabled)]
public class HomeController : Controller {
  public ActionResult Index() {
    
  
  }
}

The SessionStateBehavior Enumeration Specifies the type of session support which is one of the following values:

  • Disabled: Session state is disabled for the processing request.
  • ReadOnly: Read-only session state is enabled for the request. This means that session state cannot be updated.
  • Required: Full read-write session state behavior is enabled for the request
  • Default: The default ASP.NET logic is used to determine the session state behavior for the request.

Recall that TempData uses Session State behind the scenes, and using it in any controller that has session state disabled will throw an exception. However, it is still possible to use TempData in that case by configuring TempData to use browser cookies instead of Session State. Below is revamped code to use a browser cookie as a storage location instead of Session State.

First, you create a base class controller from which your controllers derive:

 public class ControllerBase : Controller
    {
        // Store TempData in browser's cookie instead
        protected override ITempDataProvider CreateTempDataProvider()
        {
            return new CookieTempDataProvider(HttpContext);
        }
        
    
    }

Just derive all your classes from BaseController. Here is the CookieTempDataProvider:

  public class CookieTempDataProvider : ITempDataProvider
    {
        internal const string TempDataCookieKey = "__ControllerTempData";
        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);



                return deserializedTempData;
            }

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

        protected virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
        {
            bool isDirty = (values != null && values.Count > 0);

          
            string cookieValue = SerializeToBase64EncodedString(values);  
            var cookie = new HttpCookie(TempDataCookieKey);
            cookie.HttpOnly = true;

            // Remove cookie
            if (!isDirty)
            {
                cookie.Expires = DateTime.Now.AddDays(-4.0);
                cookie.Value = string.Empty;

                _httpContext.Response.Cookies.Set(cookie);

                return;

            }
            cookie.Value = cookieValue;

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

        public static IDictionary<string, object> DeserializeTempData(string base64EncodedSerializedTempData)
        {
            byte[] bytes = Convert.FromBase64String(base64EncodedSerializedTempData);
            var memStream = new MemoryStream(bytes);
            var binFormatter = new BinaryFormatter();
            return binFormatter.Deserialize(memStream, null) as IDictionary<string, object> /*TempDataDictionary : This returns NULL*/;
        }

        public static string SerializeToBase64EncodedString(IDictionary<string, object> values)
        {
            MemoryStream memStream = new MemoryStream();
            memStream.Seek(0, SeekOrigin.Begin);
            var binFormatter = new BinaryFormatter();
            binFormatter.Serialize(memStream, values);
            memStream.Seek(0, SeekOrigin.Begin);
            byte[] 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);
        }
    }

Do not store any sensitive data inside TempData now as it is sent to the client, and it can be easily decoded with minimal effort.

I am also using twitter for posting useful tips, you can follow me at http://twitter.com/NadeemAfana

Tags:

ASP.NET | Website Optimization

Comments

jersey United States, on 6/16/2011 1:46:03 AM Said:

jersey

Thank for given Session less Controller Coding part as well to know more about Session less Controller.i m using some small programming
Thank you

Bilete Avion United States, on 11/10/2011 3:38:20 AM Said:

Bilete Avion

Dear Nadeem
May I  have your permission to use your code into my application ?
I have an small .net application and your line code are very useful for me.

Nadeem Afana United States, on 11/10/2011 6:58:07 AM Said:

Nadeem Afana

@Bilete Avion,
You can use it of course!

vsingh United Kingdom, on 11/20/2013 4:56:41 AM Said:

vsingh

while using above code I am getting exception in method : SerializeToBase64EncodedString(...) on line  
binFormatter.Serialize(memStream, values);

Type 'xyzzz.Web.Mvc.ViewModel.xyz.abc.abcModel' in Assembly 'xyzzz.Web.Mvc.ViewModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

Nadeem United States, on 11/24/2013 1:49:06 PM Said:

Nadeem

@vsingh,
The values that you need to store in a cookie must be serializable. See msdn.microsoft.com/.../ms233843.aspx for more information.

Add comment


(Will show your Gravatar icon)

  Country flag

Click to change captcha
biuquote
  • Comment
  • Preview
Loading



Google+