Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Automatic ViewState Properties with the ViewState attribute

4.85/5 (19 votes)
28 Jan 2010CPOL2 min read 44.5K  
Automatic ViewState properties.

Introduction

This article will demo how to implement automatic ViewState properties by attribute.

Background

When we create a ViewState in a page, we usually create a property for this ViewState. Like:

C#
private int ViewState_UserID
{
    get { return (int) ViewState["UserId"]; }
    set { ViewState["UserId"] = value; }
}

Do you think it is kinda boring when you try to create couple of them? Is it possible to make it simple like an Automatic Property? Like:

C#
[ViewStateProperty("UserID")]
protected int ViewState_UserID { get; set;}

or

C#
[ViewStateProperty]
protected int ViewState_UserID { get; set;}

Yes, there is a simple way to make it work by using Attribute.

Code Detail

First step, let's create a BasePage that inherits from System.Web.UI.Page. It is common to create a BasePage for a higher hierarchy. We will make use of Reflection and LINQ here.

C#
using System.Reflection;
using System.Linq;
public class BasePage : System.Web.UI.Page

The second step, create an inner class ViewStateProperty in BasePage that inherits from Attribute. The purpose of this Attribute class is to describe which property in the page is a viewstate property. Theoretically, this attribute targets the viewstate property, so it should be inside BasePage.

C#
[AttributeUsage(AttributeTargets.Property)]
public class ViewStateProperty : Attribute
{
    public string ViewStateName { get; private set; }

    internal ViewStateProperty(){
        this.ViewStateName = string.Empty;
    }

    public ViewStateProperty(string in_ViewStateName){
        this.ViewStateName = in_ViewStateName;
    }
}

[AttributeUsage(AttributeTargets.Property)] means that this attribute is only available for the property type. The public ViewStateProperty(string in_ViewStateName) constructor is to initilize the ViewState name. By default, the ViewState name is empty. If you want to initialize the ViewState name when setting the attribute, make the default constructor private.

The third step, in the BasePage, create a variable ViewStateProperties to store those properties that have the ViewStateProperty attribute and initialize them in the BasePage default constructor.

C#
private PropertyInfo[] ViewStateProperties;

protected BasePage() 
{
    this.ViewStateProperties = GetType().GetProperties(
      BindingFlags.NonPublic | BindingFlags.Instance).Where(
      p => p.GetCustomAttributes(typeof(ViewStateProperty), true).Length > 0).ToArray();
}

GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) is used to get all the public and protected properties in the page by Reflection. Where(p => p.GetCustomAttributes(typeof(ViewStateProperty), true).Length > 0) is used to filter those properies that are decorated by the ViewStateProperty attribute.

The forth step is to override the LoadViewState and SaveViewState methods in BasePage:

C#
protected override void LoadViewState(object savedState)
{
    base.LoadViewState(savedState);
    foreach (PropertyInfo property in ViewStateProperties)
    {
        ViewStateProperty[] attributes = (ViewStateProperty[])
          property.GetCustomAttributes(typeof(ViewStateProperty), false);
        var LocalName = (string.Empty == attributes[0].ViewStateName) ? 
           property.Name : attributes[0].ViewStateName;
        if (ViewState[LocalName] != null)
            property.SetValue(this, ViewState[LocalName], null);
    }
}

protected override object SaveViewState()
{
    foreach (PropertyInfo property in ViewStateProperties)
    {
        ViewStateProperty[] attributes = (ViewStateProperty[])
          property.GetCustomAttributes(typeof(ViewStateProperty), false);
        var LocalName = (string.Empty == attributes[0].ViewStateName)? 
          property.Name:attributes[0].ViewStateName;
        ViewState[LocalName] = property.GetValue(this, null);
    }
    return base.SaveViewState();
}

The goal is to set the viewstate based on the name we set in the ViewStateProperty attribute or the name of the property itself decorated by the ViewStateProperty attribute; and to load the ViewState value to the property decorated by the ViewStateProperty attribute.

Use it

As mentioned in the beginning, it is very easy to implement.

C#
[ViewStateProperty("UserID")]
protected int ViewState_UserID { get; set;}

or

C#
[ViewStateProperty]
protected int ViewState_UserID { get; set;}

In the first one, you set a ViewState called UserID, and in the second, you set a ViewState called ViewState_UserID.

Comment

To implement such properties, you can not set them as private, because GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) would not return a private property. But protected is enough for our goal.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)