Original link http://brockallen.com/2012/06/11/cookie-based-tempdata-provider/
TempData is a nice feature in MVC, if I'm not mistaken, enlighten the Flash module from the Ruby on the rails. It is basically a way of keeping a certain state across redirects.
The default implementation of Rails uses cookies to store data, which makes this quite a lightweight mechanism to pass data from one request to the next. Unfortunately, TempData's default implementation of MVC uses session state as the backing store to make it less desirable. That's why I want to show how to build an implementation that uses cookies, so here is Cookietempdataprovider.
in achieving this, it is important to acknowledge that the data stored in TempData is being sent to the client as a cookie, which means that it is open to view and modify by the end user. Therefore, I want to add protection to be modified and viewed (the modification is two more important). perform encrypted and signed Forms authentication cookies and view states using the same protection facility as the ASP. due to the limited size of cookies, we are also doing compression.
the code is available on GitHub. I also wrap this up to NuGet package (Brockallen.cookietempdata) so everything is necessary to reference the assembly through NuGet, and now all the controllers will use Cookie-based tempdata providers. If you are interested in the details of the pattern, please continue reading ...
The code is self-explanatory:
public class cookietempdataprovider:itempdataprovider{ const string cookiename = "TempData"; & nbsp; public void Savetempdata ( controllercontext controllercontext , idictionary<string, object> values) { /Convert the temp data dictionary into json String value = Serialize (values); //compress the JSON (it really helps) var bytes = Compress (value); / /sign and encrypt the data via the ASP. key value = Protect (bytes); nbsp; //Issue the cookie IssueCookie (ControllerContext, value); } Public idictionary<string, object> loadtempdata ( controllercontext ControllerContext) { //Get the cookie var value = Getcookievalue (controllercontext); /Verify and decrypt the value via the ASP. key var bytes = U Nprotect (value); //Decompress to json value = Decompress (bytes); //Convert the JSON back to a Dictionar y return Deserialize (value); } String Getcookievalue (ControllerContext controllercontext) { HttpCookie C = Controllercontext.httpcontext.request.cookies[cookiename]; if (c! = null) { return c.value; } return null; } void Issuecookie ( ControllerContext ControllerContext, String value) { HttpCookie C = new HttpCookie (cookiename, value) { //don ' t allow JavaScript access to the cookie HttpOnly = true, /Set the path so and other apps on the same server don ' t see the Cookie &nbs p; Path = controllercontext.httpcontext.request.applicationpath, //Ideally we ' re always going over SSL, but is Flexible for non-ssl apps Secure = controllercontext.httpcontext.request.issecureconnection }; if (value = = null) { /If we have a expired cookie to clear the COO with no data then issue kie c.expires = DateTime.Now.AddMonths (-1); } if (value! = NULL | | Controllercontext.httpcontext.request.cookies[cookiename]! = null) { /If we have data and then issue the COOKIE&NBSP;&NBSP; //Also, if the request has a cookie and we need to issue the COO kie //which might act as a means to clear the cookie &N bsp; CONTROLLERCONTEXT.HTTPCONTEXT.RESPONSE.COOKIES.ADD (c); } } string Protect (byte[] data) { if (data = = NULL | | data. Length = = 0) return null; return Machinekey.encode (data, Machinekeyprotection.all); } byte[] Unprotect (string value) { if (string.isnullorwhitespace (value)) return null; return Machinekey.decode (value, Machinekeyprotection.all); } byte[] Compress (string value) { if (value = = null) return null; var data = Encoding.UTF8.GetBytes (value); using (var input = new MemoryStream (data)) { using (var output = new MemoryStream ()) { using (Stream cs = new Deflatestream (output, compressionmode.compress)) { input. CopyTo (CS); } return output. ToArray (); } } } string Decompress (byte[] data) { if (data = = NULL | | data. Length = = 0) return null; using (var input = new MemoryStream (data)) & nbsp; { using ( var output = new MemoryStream ()) { using Stream cs = new Deflatestream ( Input, compressionmode.decompress)) { cs. CopyTo (output); } var result = output. ToArray (); return Encoding.UTF8.GetString (Result); } } } string Serialize (idictionary< String, object> data) { if (data = = NULL | | data. Keys.count = = 0) return null; javascriptserializer ser = new JavaScriptSerializer (); return ser. Serialize (data); } idictionary<string, OBJECT> Deserialize (string data) { if ( String.isnullorwhitespace (data)) return null; JavaScriptSerializer ser = New JavaScriptSerializer (); return ser. Deserialize<idictionary<string, object>> (data); }}
Typically, using a custom Tempdataprovider You must override Createtempdataprovider from the controller base class such as:
public class homecontroller:controller{public ActionResult Index () {return View (); } protected override Itempdataprovider Createtempdataprovider () { return new cookietemp Dataprovider (); }}
benefits-This means that you must override this in each controller or you must plan ahead and create a common controller base class for the entire application. Fortunately there is another way--tempdataprovider is not negligible on the controller base class. This means that after the controller is created, you can specify it, which is easy to do in a custom controller factory in the NuGet package:
Class cookietempdatacontrollerfactory:icontrollerfactory{ Icontrollerfactory _inner; Public cookietempdatacontrollerfactory (icontrollerfactory inner) { _inner = inner; } public IController Createcontroller (RequestContext RequestContext, string controllername) { //Pass-thru to the normal factory var Controllerinterface = _inner. Createcontroller (RequestContext, controllername); var controller = Controllerinterface as controller; if (Controller! = null) { //If we get a MVC Controller then add the cookie-based tempdata provider Controller. Tempdataprovider = new Cookietempdataprovider (); } return controller; } public Sessionstatebehavior Getcontrollersessionbehavior (RequestContext RequestContext, string controllername) { return _inner. Getcontrollersessionbehavior (RequestContext, controllername); } public void Releasecontroller (IController Controller) { _inner. Releasecontroller (Controller); }}
The last thing to do is configure the custom controller factory and do this from a separate assembly by Preapplicationstartmethod allowing code to run before Applicaton_start Magic :
[Assembly:preapplicationstartmethod (typeof (BrockAllen.CookieTempData.AppStart), "Start")]namespace brockallen.cookietempdata{public class AppStart {public static void Start () {var current Factory = ControllerBuilder.Current.GetControllerFactory (); ControllerBuilder.Current.SetControllerFactory (New Cookietempdatacontrollerfactory (currentfactory)); } }}
Original link http://brockallen.com/2012/06/11/cookie-based-tempdata-provider/
Code path
Cookie-based TempData provider