Blog Post

Saving object to HttpCookie as XML using the XMLSerializerHelper class

Ideas & Innovation
Saving object to HttpCookie as XML using the XMLSerializerHelper class
  • 26
    Oct
  • Image

Saving object to HttpCookie as XML using the XMLSerializerHelper class


This is a follow up to the previous article on XML serialization and deserialization helper class. Here I offer up some code demonstrating how to use the XmlSerializerHelper class, with some bonus code on how to save and object as XML to a cookie. I found this approach useful when I need to save some client-based settings to a cookie while leaving the class open for addition of new properties/change (as we all know happens with configuration/settings classes).

Usings

using System;
using System.Collections.Generic;
using System.Web;

Check out this article to get the XmlSerializationHelper class

I offer an approach where the class contains the code for saving and loading itself. For a solution that is adaptable to any datasource you would need to extract and interface instead of using HttpCookie, something like IDatasource (how clever!? actually better is using the Repository pattern, see Source 1: Martin Fowler, Source 2: codevil) and then pass that to the save method.

public enum Gender 
{
	Male,
	Female
}

public class Person
{
	public string Name { get; set; }
	public DateTime DateOfBirth { get; set; }
	public Gender Sex { get; set; }

	/// 
	/// Saves to the datasource as url encoded XML
	/// 
	public void Save(HttpCookie datasource)
	{
		if(datasource != null)
			datasource.Value = HttpUtility.UrlEncode(XmlSerializerHelper.ToXml(this));
	}

	/// 
	/// Restores object from url encoded XML obtained
	/// from the datasource
	/// 
	public static Person Load(HttpCookie datasource)
	{
		if (!String.IsNullOrEmpty(datasource.Value))
		{
			var decodedValue = HttpUtility.UrlDecode(datasource.Value);
			return XmlSerializerHelper.FromXml<Person>(decodedValue);
		}

		return null;
	}
}

One of the tricks to saving XML to cookies without getting an HttpRequestValidationException when request validation is enabled (see for more details), is to UrlEncode and UrlDecode the XML on save and retrieval.

HttpUtility.UrlEncode(...)
HttpUtility.UrlDecode(...)

Also don't forget to add the cookie to the response to complete the deal. Simply add

Response.Cookies.Add(datasource);

to finish saving the cookie. For more details on cookie manipulation see the following msdn article.

Comments (2)

Selmaan 17 May 2012, 03:45 AM Website

Thanks for the great post! I considered doing somenhitg wrapped around HttpValueCollection, as recommended by one commentor, but I dislike using private APIs, as they may change without notice. (I also considered the extension method, but, as I work on MANY projects, not all of which I can/should extend built-in APIs, I opted against that too: I prefer consistency to convenience.) I did rework the method you proposed to be pretty much bijective with ParseQueryString (character encoding support), which is below. ''' ''' Builds a URI query string. ''' Consider this method to be the converse of "System.Web.HttpUtility.ParseQueryString" ''' ''' NameValueCollection of query string parameters ''' Write empty parameter keys to query string ''' Query string without leading "?", suitable for use in a UriBuilder ''' Original idea from Public Shared Function BuildQueryString(ByRef parameters As NameValueCollection, Optional ByVal includeEmptyValues As Boolean = False) As String Return BuildQueryString(parameters, Nothing, includeEmptyValues) End Function ''' ''' Builds a URI query string. ''' Consider this method to be the converse of "System.Web.HttpUtility.ParseQueryString" ''' ''' NameValueCollection of query string parameters ''' Character encoding to use when UrlEncoding parameter keys and values ''' Write empty parameter keys to query string ''' Query string without leading "?", suitable for use in a UriBuilder ''' Original idea from Public Shared Function BuildQueryString(ByRef parameters As NameValueCollection, ByVal e As System.Text.Encoding, Optional ByVal includeEmptyValues As Boolean = False) As String Dim l As New List(Of String) For Each k As String In parameters.Keys Dim v As String = parameters.Item(k) If includeEmptyValues Or Not String.IsNullOrWhiteSpace(v)

Celma 19 May 2012, 05:51 AM Website

Another point What if you built the above query the other way round?Meaning you would first search all the items in the InventTable and then check the SalesLines to find all the lines where the item has been sold.My iscnintt would say to use 1:n in that case, because one incident on the master record (InventTable) would match to multiple incidents of the related table (SalesLine). You could modify the report output to give the itemid in the header and the matched sales orders in the body, to get rid of this positioning problem.Your example was 1:1, because the ItemId in the SalesLine would always match the only single incident of the same ItemId in the InventTable.This may be stupid, but the names 1:1 and 1:n sound like they were meant for this kind of use =)

New Comment

Notify me of follow up posts