ASP.NET MVC offers TempData. TempData, as the name implies, is a temporary storage. It retains the data between two user requests but no more. By default, it uses the SessionState
for storing data. A web farm has multiple servers having the application. Subsequent requests do not go to the same server. So, using session for storing TempData
is not a viable solution. Fortunately for us, TempData is customisable. This post shows how to create a custom TempDataProvider
.
Alternatives for Azure
We are developing our web application for Azure. Usually we store session data in a SQL Azure database. Using SQL Azure is more expensive. If we are not using SQL Azure for persistence, it makes sense to avoid using Session altogether.
Another option is to use the cache. In Azure, AppFabric caching is recommended. Again, this has an additional cost.
For small web applications, there is no need to use SQL Azure or AppFabric caching. But, sometimes, we need to use TempData. That is where our custom TempDataProvider
is useful. We store this data in cookies. Cookies are sent in every request. So, it works for us.
Cookie TempDataProvider
Let us say, we perform a search. An example of TempData
is our search criteria. We store the search criteria in a cookie. And retrieve it from the cookie. Our custom TempDataProvider
facilitates this. ITempDataProvider
interface has a LoadTempData
method and SaveTempData
method.
public class CookieTempDataProvider : ITempDataProvider { private const string TempDataCookie = "TempData"; public IDictionary<string, object> LoadTempData(ControllerContext controllerContext) { } public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) { } }
A custom TempDataProvider
implements the ITempDataProvider
interface. We start with implementing the SaveTempData
method.
public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) { HttpResponseBase res = controllerContext.RequestContext.HttpContext.Response; HttpCookie cookie = res.Cookies.Get(TempDataCookie); if (cookie == null) { cookie = new HttpCookie(TempDataCookie); res.Cookies.Add(cookie); } foreach (KeyValuePair<string, object> kvp in values) { BinaryFormatter formatter = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { formatter.Serialize(ms, kvp.Value); byte[] bytes = ms.GetBuffer(); string base64Value = Convert.ToBase64String(bytes); string keyExists = cookie.Values.Get(kvp.Key); if (keyExists != null) { cookie.Values.Set(kvp.Key, base64Value); } else { cookie.Values.Add(kvp.Key, base64Value); } } } }
The cookie name is TempData
. In the above code, we create a new cookie or use the existing cookie. Also, cookies store only string data. TempData
is usually an object. We use the BinaryFormatter
to serialize the object into a string. Set the cookie value to the Base64 string.
LoadTempData
method does the reverse. We retrieve the TempData
from the cookie.
public IDictionary<string, object> LoadTempData(ControllerContext controllerContext) { HttpRequestBase req = controllerContext.RequestContext.HttpContext.Request; HttpCookie cookie = req.Cookies[TempDataCookie]; Dictionary<string, object> tempData = new Dictionary<string, object>(); if (cookie != null) { for (int keyIndex = 0; keyIndex < cookie.Values.Count; keyIndex++) { string key = cookie.Values.GetKey(keyIndex); if (!string.IsNullOrEmpty(key)) { string base64Value = cookie.Values.Get(keyIndex); byte[] buffer = Convert.FromBase64String(base64Value); using (MemoryStream ms = new MemoryStream(buffer)) { BinaryFormatter formatter = new BinaryFormatter(); object value = formatter.Deserialize(ms); tempData.Add(key, value); } } } } return tempData; }
Get the TempData
cookie. From the cookie, convert each key value pair into a TempData
dictionary. Deserialize the value from its Base 64 representation to an object.
Finally, add the TempDataProvider
to the base controller.
public BaseController(ITempDataProvider tempDataProvider) { this.TempDataProvider = tempDataProvider; }
We are all set to use TempData
in our Azure applications.