Friday 30 July, 2010

How to compress ViewState In ASP.NET

Http is a stateless protocol. Hence the ‘page-state-information’ is not saved between postbacks. In ASP.NET, viewstate is the means of storing the state of server side controls between postbacks. It contains a snapshot of the contents of a page. The information is stored in HTML hidden fields.
The viewstate is quiet handy in most cases as it does a lot of work for you in saving the state of controls. However it comes with a cost. If your page contains a lot of controls holding a large amount of data, you can imagine the load when this data is transferred to and from the browser on each postback. It gradually increases the size of your page, thereby leading to performance issues. Well you can get around this problem by disabling viewstate for controls, where maintaining state is not required (EnableViewState=false). However, in scenarios, where maintaining the state of controls is required, compressing viewstate helps improve performance.
Using System.IO.Compression
In ASP.NET 1.1, developers used custom compression tools like ICSharpCode.SharpZipLib to compress viewstate. ASP.NET 2.0 provides us with the System.IO.Compression namespace, which contains classes with functionality to compress and decompress streams. This namespace contains two classes called DeflateStream and GZipStream that provides methods and properties to compress and decompress streams.
Compressing/Decompressing using GZipStream
The compression functionality in GZipStream is exposed as a stream. In the code displayed below, we will create a class called ViewStateCompressor that contains two methods :
Compress(byte[] array) - Accepts a decompressed bytearray, compresses it and returns a compressed bytearray.
Decompress(byte[] array) – Accepts compressed bytearray, decompresses it and returns a decompressed bytearray.
The code has been commented to help you understand each method.
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;
using System.IO;
using System.IO.Compression;
///
/// Summary description for ViewStateCompressor
///
public class ViewStateCompressor
{
public ViewStateCompressor()
{
//
// TODO: Add constructor logic here
//
}
public static byte[] CompressViewState(byte[] uncompData)
{
using (MemoryStream mem = new MemoryStream())
{
CompressionMode mode = CompressionMode.Compress;
// Use the newly created memory stream for the compressed data.
using (GZipStream gzip = new GZipStream(mem, mode, true))
{
//Writes compressed byte to the underlying
//stream from the specified byte array.
gzip.Write(uncompData, 0, uncompData.Length);
}
return mem.ToArray();
}
}
public static byte[] DecompressViewState(byte[] compData)
{
GZipStream gzip;
using (MemoryStream inputMem = new MemoryStream())
{
inputMem.Write(compData, 0, compData.Length);
// Reset the memory stream position to begin decompression.
inputMem.Position = 0;
CompressionMode mode = CompressionMode.Decompress;
gzip = new GZipStream(inputMem, mode, true);
}
using (MemoryStream outputMem = new MemoryStream())
{
// Read 1024 bytes at a time
byte[] buf = new byte[1024];
int byteRead = -1;
byteRead = gzip.Read(buf, 0, buf.Length);
while (byteRead <= 0)
{
//write to memory stream
outputMem.Write(buf, 0, byteRead);
byteRead = gzip.Read(buf, 0, buf.Length);
}
gzip.Close();
return outputMem.ToArray();
}
}
}
Utilizing the ViewStateCompressor class
Once we have created the functionality of compressing and decompressing viewstate, its time to use this functionality in our webpages. For this, create a CustomPage which inherits from System.Web.UI.Page. In the CustomPage, you will need to override the LoadPageStateFromPersistenceMedium() and SavePageStateToPersistenceMedium() to serialize and deserialize viewstate. We require this customization because we are compressing the viewstate. All the other web pages in the application will inherit from this BasePage.
The LoadPageStateFromPersistenceMedium() method has been overridden here to decompress the bytes stored in hidden field “_CustomViewState”. The steps performed are as follows :
· The compressed viewstate stored in this field is encoded as Base64 string.
· The Convert.FromBase64String(viewState) converts it into byte array.
· It’s time to call the DecompressViewState() method we created earlier.
· This method returns a bytearray containing decompressesed data which is converted back to Base64 string.
· Finally the LosFormatter class is used to deserialize the view state.
The SavePageStateToPersistenceMedium() method accepts a ViewState object. The Serialize() method of the LosFormatter class accepts a stream and the viewstate object. If you have already observed, we are performing a reverse operation of what we did in the LoadPageStateFromPersistenceMedium() method. We will first serialize, compress and then encode data in Base64. This Base64 string is then saved into the “_CustomViewState” hidden field.
The code has been given below :
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;
using System.IO;
///
/// Summary description for CustomPage
///
public partial class CustomPage : Page
{
public CustomPage()
{
//
// TODO: Add constructor logic here
//
}
// Serialize view state
protected override void SavePageStateToPersistenceMedium(object pageViewState)
{
LosFormatter losformatter = new LosFormatter();
StringWriter sw = new StringWriter();
losformatter.Serialize(sw, pageViewState);
string viewStateString = sw.ToString();
byte[] b = Convert.FromBase64String(viewStateString);
b = ViewStateCompressor.CompressViewState(b);
ClientScript.RegisterHiddenField("__CUSTOMVIEWSTATE", Convert.ToBase64String(b));
}
// Deserialize view state
protected override object LoadPageStateFromPersistenceMedium()
{
string custState = Request.Form["__CUSTOMVIEWSTATE"];
byte[] b = Convert.FromBase64String(custState);
b = ViewStateCompressor.DecompressViewState(b);
LosFormatter losformatter = new LosFormatter();
return losformatter.Deserialize(Convert.ToBase64String(b));
}
}
There you go!! Use these classes and hopefully your ViewState size will be reduced by 30-40%.
References
There are a number of good resources I referred to for this article. A few of them are:
http://www.dotnetbips.com/articles/22d33d11-1a75-42c8-bbf6-ca1a345d3fcf.aspx
http://www.codeproject.com/aspnet/ViewStateCompression.asp
http://www.eggheadcafe.com/articles/20040613.asp
http://msdn2.microsoft.com

Thursday 29 July, 2010

GridView Tips and Tricks using ASP.NET

The GridView control is quiet a handy control and is the most commonly used control when building an ASP.NET site. The more you work with it, the more you realize how powerful it can be while presenting data.
Moving ahead with our GridView Tips and tricks series, I have added some more tips in this article. The previous two articles on the Tips and Tricks are mentioned below:
For this article, we would be using the following template to populate the GridView.
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>GridView Tips and Tricks Part 2title>
head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="CategoryID"
DataSourceID="SqlDataSource1" ShowFooter="true" AllowPaging="True" AllowSorting="True"
PageSize="5" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="CategoryID" InsertVisible="False" SortExpression="CategoryID">
<ItemTemplate>
<asp:Label ID="lblCategoryID" runat="server" Text='<%# Bind("CategoryID") %>'>asp:Label>
ItemTemplate>
asp:TemplateField>
<asp:TemplateField HeaderText="CategoryName" SortExpression="CategoryName">
<EditItemTemplate>
<asp:TextBox ID="txtCategoryName" runat="server" Text='<%# Bind("CategoryName") %>'>asp:TextBox>
EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblCategoryName" runat="server" Text='<%# Bind("CategoryName") %>'>asp:Label>
ItemTemplate>
asp:TemplateField>
<asp:TemplateField HeaderText="Description" SortExpression="Description">
<EditItemTemplate>
<asp:TextBox ID="txtDesc" runat="server" Text='<%# Bind("Description") %>'>asp:TextBox>
EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lblDesc" runat="server" Text='<%# Bind("Description") %>'>asp:Label>
ItemTemplate>
asp:TemplateField>
Columns>
asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="Data Source=SUPROTIM;Initial Catalog=Northwind;Integrated Security=True"
ProviderName="System.Data.SqlClient" SelectCommand="SELECT [CategoryID], [CategoryName], [Description] FROM [Categories]"
UpdateCommand="UPDATE [Categories] SET [CategoryName] = @CategoryName, [Description] = @Description WHERE [CategoryID] = @CategoryID"/>
div>
form>
body>
html>
The web.config holding the connection will look similar to the following:
<configuration>
<appSettings/>
<connectionStrings>
<add name="NorthwindConnectionString" connectionString="Data Source =(local);Integrated Security = SSPI; Initial Catalog=Northwind;"/>
connectionStrings>
...
configuration>
Tip 1: Change the color of a GridView Row based on some condition
C#
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.DataItem != null)
{
DataRowView drv = (DataRowView)e.Row.DataItem;
string catName = Convert.ToString(drv["CategoryName"]);
if (catName.Trim() == "Confections")
e.Row.BackColor = System.Drawing.Color.LightBlue;
}
}
VB.NET
Protected Sub GridView1_RowCreated(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If Not e.Row.DataItem Is Nothing Then
Dim drv As DataRowView = CType(e.Row.DataItem, DataRowView)
Dim catName As String = Convert.ToString(drv("CategoryName"))
If catName.Trim() = "Confections" Then
e.Row.BackColor = System.Drawing.Color.LightBlue
End If
End If
End Sub