Pass Classes in ASP.NET with LosFormatter
By Peter A. Bromberg, Ph.D.
Printer - Friendly Version
Peter Bromberg
There are a number of ways to serialize and store objects in the ASP.NET Runtime - the Session collection, Cache object, Application state, the HhttpContext.Items collection, and more. String type items can be passed on the querystring or in hidden Form fields as well. Object Graphs can also be stored in the AppDomain Cache where they are available to any assembly running in the same AppDomain, for example a database class library assembly that may be used by an ASP.NET page, but does not explicitly derive from any of the System.Web namespace classes and therefore does not have access to the Session, Cache, etc. objects.


Here I want to preview a somewhat different method of persisting state - one where you can serialize a live class instance, pass it to another ASP.NET page, deserialize it into a new instance of the same type, and use the properties and members as you see fit. In a previous article, "Serialize/Deserialize Classes into SQL Server", I showed how it is possible to use the BinaryFormatter class and persist live objects to a database.
We will also use the BinaryFormatter class here, a member of the System.Runtime.Serialization.Formatters namespace, in this article. However, I also want to highlight a little - known, undocumented class : LosFormatter. LosFormatter, a member of the System.Web.UI namespace, is a "stripped down" version of BinaryFormatter that is used internally by the ASP.NET runtime to create and retrieve Page - level objects to / from the hidden _VIEWSTATE field.
LosFormatter, although undocumented, can also be easily used explicitly by the developer. One of the handy features it has is that the serialized string it generates is automatically Base64 encoded so that the ViewState Collection can be persisted through page POSTs. Of course, if you explicitly call the methods of LosFormatter, you are not restricted to keeping the resulting string in the hidden _VIEWSTATE field - you can do whatever you want with it.
Let's start out with a simple class that can be easily populated with a public string member and a public ArrayList member:
using System;
using System.Collections;

namespace PAB
{
	[Serializable]
	public  class theClass  
	{
		public  string TheString =String.Empty;
		public  ArrayList TheArrayList= new ArrayList();
		public  void setMeUp(string theString, ArrayList theArrayList)
		{
			TheString=theString;
			TheArrayList=theArrayList;
		}
	}
}
Note that we need to decorate our class with [SerializableAttribute] or else we would need to create custom serialization code in order to use any of the members of the Formatters namespace.
Now let's take a look at the methods we'll use for the LosFormatter:

private string SaveObjectToViewState(object  obj)
{
System.Web.UI.LosFormatter output = new System.Web.UI.LosFormatter();
StringWriter writer = new StringWriter();
output.Serialize(writer, obj);
return writer.ToString(); 

} 

private object RetrieveObjectFromViewState( string viewstate)
{
System.Web.UI.LosFormatter input = new System.Web.UI.LosFormatter();
return input.Deserialize(viewstate);

}
SaveObjectToViewState accepts an object parameter (the class instance you want to serialize) , and uses the LosFormatter.Serialize method, which can accept either a Stream or a TextWriter to write the Limited Object Serialization (LOS) result into. You can, of course, call these methods anything you want. However, you can also override the intrinsic Page.SavePageStateToPersistenceMedium and the Page.LoadPageStateFromPersistenceMedium methods, which expect the hidden field "_VIEWSTATE" to be present.
These methods use the System.Web.UI.Triplet class, which is designed to hold three values making up the state (or a portion of the state) of the various controls on the page so that on a postback, the control states can be restored. The internal XML representation of  Triplet looks like the following:
<?xml version="1.0" encoding="utf-16"?>
<viewstate>
<triplet>
<string>-1279334384</string>
<string>whatever </string>
<string>whoever </string>
</triplet>
</viewstate>
We will also need to add the methods used for the BinaryFormatter:
 

public byte[] SerializeAndSave(object c)
{
   try
    {
        MemoryStream ms = new MemoryStream();
        BinaryFormatter b = new BinaryFormatter();
        b.Serialize(ms,c);
        return ms.ToArray();
    }
    catch(Exception ex)
    {
        throw new Exception(ex.Message);
    }
}

public object RetrieveAndDeserialize(byte[] buf )
{
   try
   {
     MemoryStream ms2 = new MemoryStream();
     ms2.Write (  buf,0,buf.Length ); 
     ms2.Seek(0,0);
     BinaryFormatter b=new BinaryFormatter(); 
     object c =b.Deserialize(ms2);   			 
     ms2.Close();  		       
     return c;
   }
   catch(Exception ex)
   {
    throw new Exception(ex.Message);
    }
}
In our Page_Load handler on our first page, we will create a new instance of  "theClass ", and call the SetMeUp method to populate its public members:

  private void Page_Load(object sender, System.EventArgs e) 
	{
	ArrayList al = new ArrayList();
	al.Add("This is the First ArrayList element (ArrayList[0])");
	al.Add("This is the second ArrayList elenent (ArrayList[1])");
	string myString = "Hello There!  I am a string! (myString)";
	theClass tc = new theClass();
	// populate our public class members with the setMeUp method...
	tc.setMeUp(myString, al);
	// Serialize using BinaryFormatter...
	byte[] b = SerializeAndSave(tc);
	string s = Server.UrlEncode(System.Text.Encoding.Default.GetString(b));
	//assign (string)BinaryFormatter object graph to hidden field
	hiddenView.Value=s;
	lblMessage.Text=s; 
	  // serialize using LosFormatter..
	string s2 = Server.UrlEncode(SaveObjectToViewState(tc));
	// Assign LosFormatter object graph to hidden field
	hiddenView2.Value =s2;
	 tc=null;
	// if form is posted, get back new instance of 
	// the populated serialized class..
if(IsPostBack)
 {
object obj=RetrieveAndDeserialize( 
	 System.Text.Encoding.Default.GetBytes(Server.UrlDecode(hiddenView.Value)));
theClass tc2 = (theClass)obj;
lblMessage.Text="RESULT: " +tc2.TheString;
lblMessage.Text+= "
" + tc2.TheArrayList[0].ToString() + "
" +tc2.TheArrayList[1].ToString(); } } // end pageload

What we do here is create an instance of the "theClass" class, populate its TheString and TheArrayList members, and pass the instance into both the BinaryFormatter and the LosFormatter serialize methods. We use UrlEncode on the BinaryFormatter method because it doesn't intrinsically apply HTML - safe encoding to the byte array it generates. The strings are stored in the two hidden fields, hiddenView and hiddenView2 respectively.
We have a button on our first page that does a postback, and in our Page_Load we have the if(IsPostBack) section that extracts our class by sending the UrlDecoded hiddenView field contents back through the RetrieveAndDeserialize BinaryFormatter (you can do it with the LosFormatter field too, I've just saved that for the second page).
We also have another button on our page that posts to the second page:
<form action="losFormatter2.Aspx" method="post">
<input type="hidden" id="hiddenView" name="hiddenView" runat="server">
<input type="submit" VALUE="Next Page!">
<input type="hidden" id="hiddenView2" name="hiddenView2" runat="server">&nbsp;
</form>
As you can see, this second Form is also the one that holds the two hidden fields (Yes, you can have as many forms as you want on an ASP.NET page; but only one can have the runat=server directive).
Now in our second page that receives the POST, we have:

private void Page_Load(object sender, System.EventArgs e) 
{
lblMessage2.Text= Request.Params["hiddenView"].Trim();

// first get object from BinaryFormatter (hiddenView)
object tc=RetrieveAndDeserialize(System.Text.Encoding.Default.GetBytes(
      Server.UrlDecode(Request.Params["hiddenView"])));
theClass tc2=(theClass) tc;
lblMessage.Text="RESULT: " +tc2.TheString;
lblMessage.Text+= "
" + tc2.TheArrayList[0].ToString() + "
" +tc2.TheArrayList[1].ToString(); // now deserialize object from LosFormatter (hiddenView2) object obj =RetrieveObjectFromViewState(Server.UrlDecode( Request.Params["hiddenView2"])); theClass tc3=(theClass)obj; lblMessage2.Text="RESULT: " +tc3.TheString; lblMessage2.Text+= "
" + tc3.TheArrayList[0].ToString() + "
" +tc3.TheArrayList[1].ToString(); }
This accepts the two hidden field values and passes them to the same two deserializer methods, and writes the ArrayList values and the String value of the passed-in class to the two label controls on the page. Presto! You now have a simple mechanism to pass classes around from page to page. You can download the full solution in C# at the link below.
Download the code that accompanies this article
 

Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.