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:
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:
[ViewStateProperty("UserID")]
protected int ViewState_UserID { get; set;}
or
[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.
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
.
[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.
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
:
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.
[ViewStateProperty("UserID")]
protected int ViewState_UserID { get; set;}
or
[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.