I started to search for more information on what i was doing found a good posting from Steven Swafford On Using Application Cache for viewstate.

His post also refers to a asp.net podcast that talks about the same thing. It is good if your application is on one server or Your farm is using sticky session. But it is still a good idea, i emailed him asking permission to take some of the code and create a Viewstate Storage medium for ViewStateEliminator.

I have hit a small snag when it comes to the average life expectancy of and keeping its viewstate around. should I really keep it around anymore than a couple of hours. I understand that the point of viewstate was to have a way to rebuild the control tree with out having to keep the information on the server.

But the increasing size of viewstate to client is becoming alarmingly large on the complex and large web applications.

a solution that a friend of mine sugested is that if we use SQL server as a storage medium only keep viewstate up to 24 hours and then simply delete them. Or through a configuration in the web config

This is a solution for stripping out viewstate before it hits the client. The thought for making this utility was the following, viewstate has no real use fullness on they client besides reconstructing the control tree and as a state bag. Most of the time developers turn viewstate off on controls because it tends to become huge and slows down the streaming of content.

Even when using Ajax API’s such as Microsoft Ajax and Anthem.Net viewstate is still passed back and forth. So even though we get partial page updates we are still passing through that big chunk back and forth, watch we have done is we have disguised the problem but not solve it.

What has been done is eliminated viewstate being sent out to the client and being stored in another medium.

Current Supported mediums:

  1. SQL Database
  2. Session

SQLDatabase is inserting viewstate into a table given certain keys.

Session was chosen as a storage method also after a friend asked me “so what are you doing sticking it in session?”….I answered no. Then it got me to thinking well…what if i do store it in session…what would be so bad? Session…well what would be the impact of the different flavors of session..

  1. InProc Session: I would avoid a round trip to the server and it would be saved in memory…If i also compress it it shouldn’t be so bad.
  2. Session State Server: In this case i piggy back of the session state server and double it as a viewstate server as well.

The Session & Database methods helps the issue of retrieving the right viewstate from a web farm.

So I have put a W.I.P version on codeplex that i will be updating on the weekend….I know right now its not Pure OO … its not something that Jean-Paul S Boodhoo would approve lol

http://www.codeplex.com/ViewStateEliminator

I know i been away but here is part three, this version checks your Asp_net role and the roles for a current node. Veri simple but the menu looks very cool

[Serializable()]
public class CssMenu : Panel
{
private SiteMapDataSource xds;
private string[] userRoles;

private bool HasRoles(SiteMapNode item)
{

bool retval = false;
foreach (string item2 in item.Roles)
{
if (item2.ToString().Equals("*"))
retval = true;
foreach (string item1 in userRoles)
{
if (item1.Equals(item2.ToString()))
retval = true;
}
}
return retval;
}

public SiteMapDataSource DataSource
{
get
{
return xds;
}

set
{
xds = value;
}
}
///
///
///
public string CssId
{
get
{
if (ViewState["CssId"] == null)
ViewState["CssId"] = "";
return (string)ViewState["CssId"];
}
set
{
ViewState["CssId"] = value;
}
}
///
///
///
public bool StartAtRoot
{
get
{
if (ViewState["StartAtRoot"] == null)
return false;
return (bool)ViewState["StartAtRoot"];
}
set
{
ViewState["StartAtRoot"] = value;
}
}
///
///
///
public string CssCurrentClass
{
get
{
if (ViewState["CssCurrentClass"] == null)
ViewState["CssCurrentClass"] = "";

return (string)ViewState["CssCurrentClass"];
}
set
{
ViewState["CssCurrentClass"] = value;
}
}
///
///
///
public int ChildLevels
{
get
{
if (ViewState["ChildLevels"] == null)
ViewState["ChildLevels"] = 1;

return (int)ViewState["ChildLevels"];
}
set
{
ViewState["ChildLevels"] = value;
}
}
///
///
///
private void LoaChildsNodes(SiteMapNodeCollection smnc, ref Panel obj)
{
Literal lit = new Literal();
lit.Text = " ";
      obj.Controls.Add(lit);
      foreach (SiteMapNode item in smnc)
      {
      //if (this.HasRoles(item.Roles))
      // {
      lit = new Literal();
      lit.Text = "* ";
      obj.Controls.Add(lit);
      HyperLink lnk = new HyperLink();
      lnk.Text = item.Title;
      lnk.NavigateUrl = item.Url;
      if (Page.Request.RawUrl.ToLower().Contains(item.Url.ToLower()) && (CssCurrentClass.Length > 0))
      lnk.CssClass = CssCurrentClass;
      else
      lnk.CssClass = "";
      obj.Controls.Add(lnk);
      lit = new Literal();
      lit.Text = "  ";
      obj.Controls.Add(lit);
      // }

      }
      lit = new Literal();
      lit.Text = "";
obj.Controls.Add(lit);
}
protected override void OnDataBinding(EventArgs e)
{
base.Controls.Clear();
base.OnDataBinding(e);
SiteMapNodeCollection smnc;
userRoles = Roles.GetRolesForUser();
xds = this.DataSource;
if (StartAtRoot)
smnc = xds.Provider.GetChildNodes(xds.Provider.RootNode);
else
smnc = xds.Provider.GetChildNodes(xds.Provider.CurrentNode);

Literal lit = new Literal();
lit.Text = "";
      base.Controls.Add(lit);

      foreach (SiteMapNode item in smnc)
      {
      if (HasRoles(item))
      {
      lit = new Literal();
      lit.Text = " * ";
      base.Controls.Add(lit);
      HyperLink lnk = new HyperLink();
      lnk.Text = item.Title;
      lnk.NavigateUrl = item.Url;
      if (Page.Request.RawUrl.ToLower().Contains(item.Url.ToLower()) && (CssCurrentClass.Length > 0))
      {
      lnk.CssClass = CssCurrentClass;
      }
      else
      {
      lnk.CssClass = "";
      }
      base.Controls.Add(lnk);
      SiteMapNodeCollection smc2 = xds.Provider.GetChildNodes(item);
      if ((this.ChildLevels > 1) && (smc2.Count > 0))
      {

      Panel pn = new Panel();
      lit = new Literal();
      lit.Text = "";
      pn.Controls.Add(lit);
      this.LoaChildsNodes(xds.Provider.GetChildNodes(item), ref pn);
      lit = new Literal();
      lit.Text = "";
      pn.Controls.Add(lit);
      base.Controls.Add(pn);
      }
      lit = new Literal();
      lit.Text = "";
      base.Controls.Add(lit);
      }
      }
      lit = new Literal();
      lit.Text = "";
base.Controls.Add(lit);

}

}

I didn’t post any css in my previous post for the use of the menu control this is the css i used when i was creating it. The Menu Id is a horizontal menu and Nav Id is a vertical menu, as you can see all i have to do is assign the CssId to the control and we manage the look with css and the content in code.

My next post will be about using the Roles to determine access to the user.

Sample CSS:

/**** Main Menu ***/

#menu {
display: block;
float:right;
}

#menu ul {
margin: 0;
list-style: none;
}

#menu li {
display: block;
float: left;
white-space: nowrap;
}

#menu li a {
display: block;
padding: 55px 20px 12px 20px;
text-decoration: none;
color: #fff;
font-weight: bold;
}

* html #menu a {width:1%;}

#menu li a:hover {
background: url(../img/bg_menu.gif);
}

#menu li a.current {
letter-spacing: 1px;
color: gray;
background: url(../img/bg_menu.gif);
}

#menu li a.current:hover {
color: #fff;
}


/**** nav ***/
#nav{ list-style: none; margin: 2.0em 0; width: 25em; float: right;}
#nav li{ padding: 0; margin: 0; }
#nav a{
display: block;
height: 2.0em;
padding: 0.3em 0.3em 0.3em 0.8em;
border-bottom: 2px; /*solid #1a1a1a*/
border-top: 2px; /*solid #1a1a1a*/
color: #93B300;
background-color: #F7F9FB;
font-weight: bold;
text-decoration: none;
}

#nav a:hover{
color: #1a1a1a;
background: url(../img/bg_t.gif) no-repeat;
background-color: #fff;
font-weight: bold;
} 

As you can see from the code bellow it is very easy to create a Server Control that takes in a SiteMapDataSource. Simply get a SiteMapNodeCollection  from the provider and iterate through it and build your html.

This way you can create controls to fit your design and still have all the ability to manage your site from the xml file. Also you are able to get all the roles and user accessibility for each node.

Source Code:

using System;

using System.Data;

using System.Configuration;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

namespace Yournamespace.UI.WebControls
{

///

/// Summary description for MenuTop

///

[ Serializable()]

public class MenuSiteMap : Panel

{

private SiteMapDataSource xds;

public SiteMapDataSource DataSource

{

get

{

return xds;

}

set

{

xds = value;

}

}

protected override void OnDataBinding(EventArgs e)

{

base.Controls.Clear();

base.OnDataBinding(e);

SiteMapNodeCollection smnc;

xds = this.DataSource;

smnc = xds.Provider.GetChildNodes( xds.Provider.RootNode);

Literal lit = new Literal();

lit.Text = ”

    “;

    base.Controls.Add(lit);

    foreach (SiteMapNode item in smnc)

    {

    lit = new Literal();

    lit.Text = ”

  • “;

    bse.Controls.Add(lit);

    HyperLink lnk = new HyperLink();

    lnk.Text = item.Title;

    lnk.NavigateUrl = item.Url;

    base.Controls.Add(lnk);

    lit = new Literal();

    lit.Text = ”

    “;

    base.Controls.Add(lit);

    }

    lit = new Literal();

    lit.Text = “

“;

base.Controls.Add(lit);

base.Controls.Add(lit);
}
}
}