Saving server control properties to ViewState with custom attributes
One thing I don’t like about creating ASP.NET server controls is you end up with a lot of properties that look like this:
-
public class PieControl1 : Control{
-
…
-
public int Pies
-
{
-
get
-
{
-
if (ViewState["Pies"] != null)
-
return (int)ViewState["Pies"];
-
return 0;
-
}
-
set { ViewState["Pies"] = value;}
-
}
It’s dull, dull, dull code to write! We are programmers. Our job is to dream of beautiful abstractions and clever solutions to difficult problems. It is our machine underlings who should do the boring work like this!
Fortunately, there is an alternative. C# has a really nifty feature called Attributes that you can use to add meta data to your class. If you’ve made server controls before you’ve probably used them for things like web resources, toolbox information and serialization.
So we just need to create a new attribute:
-
[AttributeUsage(AttributeTargets.Property)]
-
public class PersistToViewState : Attribute
-
{
-
}
And then just add it to any property in the server control that should get persisted in ViewState. If you’re using the property shorthand in C# 3.5 you can end up with properties that are only one line long:
-
public class PieControl : BaseControl
-
{
-
…
-
[PersistToViewState]
-
public string PieType { get; set; }
-
-
[PersistToViewState]
-
public int Pies { get; set; }
-
}
Now it’s possible to use a little reflection to figure out which properties need to be saved. Load the viewstate information into the control in LoadViewState and then save it back again in SaveViewState. In my example, I put it in a BaseControl so all my controls can use the same logic:
-
public class BaseControl : Control
-
{
-
protected override void LoadViewState(object savedState)
-
{
-
base.LoadViewState(savedState);
-
PropertyInfo[] properties = GetType().GetProperties();
-
foreach (PropertyInfo property in properties)
-
{
-
object[] attributes = property.GetCustomAttributes(typeof(PersistToViewState), true);
-
if (attributes.Length < 0)
-
{
-
if (ViewState[property.Name] != null)
-
property.SetValue(this, ViewState[property.Name], null);
-
}
-
}
-
}
-
protected override object SaveViewState()
-
{
-
PropertyInfo[] properties = GetType().GetProperties();
-
foreach (PropertyInfo property in properties)
-
{
-
object[] attributes = property.GetCustomAttributes(typeof(PersistToViewState), true);
-
if (attributes.Length < 0)
-
ViewState[property.Name] = property.GetValue(this, null);
-
}
-
return base.SaveViewState();
-
}
-
}
Here’s a complete example.
For more information there’s a follow up post that shows how to use this technique to optimize the amount of viewstate generated.







Comments
Good idea, wondered why Microsoft didn’t implement this.
Really useful, thanks.
Nice work, I made a slight alteration to your LoadViewstate method to enable use of the default value attribute:
if (ViewState[property.Name] != null)
property.SetValue(this, ViewState[property.Name], null);
else
{
// Load the default value instead
attributes = property.GetCustomAttributes(typeof(DefaultValueAttribute), true);
if (attributes.Length > 0)
{
DefaultValueAttribute dva = (DefaultValueAttribute)attributes[0];
property.SetValue(this, dva.Value, null);
}
}
There’s a more efficient way to do this in the recent version of C#:
public class PieControl1 : Control
{
…
public int Pies
{
get { return (int) (ViewState["Pies"] ?? 0); }
set { ViewState["Pies"] = value; }
}
}
The new ?? operator says, “Use the value if it is not null, or else use the second operand if it is.” So if ViewState["Pies"] is null, a 0 will be returned. Otherwise, the value of ViewState["Pies"] will be returned.
mmm, i’ve been toying with using something like this.
I think the reflection overhead might just be a bit too much to save what would be now (with the ?? operator, a couple of lines of code (give or take the curlys):
[PersistToViewState]
public string PieType { get; set; }
public int Pies
get { return (int) (ViewState["Pies"] ?? 0); }
set { ViewState["Pies"] = value; }
Trackbacks