|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionIn my first CodeProject article. I'll show how to encapsulate the access to objects stored in the BackgroundASP.NET development is great. Using code-behind classes, user controls, datasets, and encapsulating the application business logic, ASP.NET development (almost) turned into pleasure. But sometimes you find yourself in need to write code that reads and writes to the That's when attributes and reflection come in handy - so you don't need to type all those casts. This sample code relies on tagging fields of a WebForm using an attribute, and then subclassing the Declaring the MetadataWe need to create an attribute, so we can mark the WebForm fields we want to be persisted. [AttributeUsage(AttributeTargets.Field)]
public class PersistFieldAttribute : Attribute
{
PersistLocation loc;
string key;
public PersistFieldAttribute()
: this(PersistLocation.Nowhere, null)
{
}
public PersistFieldAttribute(PersistLocation location)
: this(location, null)
{
}
public PersistFieldAttribute(PersistLocation location, string key)
{
Location = location;
Key = key;
}
public string GetKeyFor(MemberInfo mi)
{
return (Key != null ? Key + "_" + mi.Name : mi.Name);
}
public string Key
{
get { return key; }
set { key = value; }
}
public PersistLocation Location
{
get { return loc; }
set { loc = value; }
}
public static PersistFieldAttribute GetAttribute(MemberInfo mi)
{
return (PersistFieldAttribute) Attribute.GetCustomAttribute(mi,
typeof(PersistFieldAttribute));
}
public static PersistFieldAttribute GetAttribute(MemberInfo mi,
PersistLocation forLocation)
{
PersistFieldAttribute attr = GetAttribute(mi);
return (attr != null && attr.Location == forLocation ? attr : null);
}
}
I also added some helper (and type-safe) static Of course, we also need to declare the public enum PersistLocation
{
Nowhere = 0x00,
Context = 0x01,
ViewState = 0x02,
Session = 0x04,
Application = 0x08,
}
(YES, I like to explicitly declare the enumeration values) Overriding System.Web.UI.PageWe'll need to override these four methods: using System;
using System.Reflection;
using System.Web.UI;
public class PageEx : Page
{
const BindingFlags FieldBindingFlags =
BindingFlags.Instance|BindingFlags.NonPublic;
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
foreach (FieldInfo fi in GetType().GetFields(FieldBindingFlags))
{
PersistFieldAttribute attr =
PersistFieldAttribute.GetAttribute(fi, PersistLocation.ViewState);
if (attr != null)
{
TrySetValue(fi, ViewState[attr.GetKeyFor(fi)]);
}
}
}
protected override object SaveViewState()
{
foreach (FieldInfo fi in GetType().GetFields(FieldBindingFlags))
{
PersistFieldAttribute attr =
PersistFieldAttribute.GetAttribute(fi, PersistLocation.ViewState);
if (attr != null)
ViewState[attr.GetKeyFor(fi)] = TryGetValue(fi);
}
return base.SaveViewState();
}
protected override void OnInit(EventArgs e)
{
foreach (FieldInfo fi in GetType().GetFields(FieldBindingFlags))
{
PersistFieldAttribute attr = PersistFieldAttribute.GetAttribute(fi);
if (attr != null)
{
switch (attr.Location)
{
case PersistLocation.Application:
TrySetValue(fi, Application[attr.GetKeyFor(fi)]);
break;
case PersistLocation.Context:
TrySetValue(fi, Context.Items[attr.GetKeyFor(fi)]);
break;
case PersistLocation.Session:
TrySetValue(fi, Session[attr.GetKeyFor(fi)]);
break;
}
}
}
base.OnInit(e);
}
protected override void OnUnload(EventArgs e)
{
base.OnUnload(e);
foreach (FieldInfo fi in GetType().GetFields(FieldBindingFlags))
{
PersistFieldAttribute attr = PersistFieldAttribute.GetAttribute(fi);
if (attr != null)
{
switch (attr.Location)
{
case PersistLocation.Application:
Application[attr.GetKeyFor(fi)] = TryGetValue(fi);
break;
case PersistLocation.Context:
Context.Items[attr.GetKeyFor(fi)] = TryGetValue(fi);
break;
case PersistLocation.Session:
Session[attr.GetKeyFor(fi)] = TryGetValue(fi);
break;
}
}
}
}
}
Using the attributesThat's the simplest part: public class MyCustomPage : PageEx
{
[PersistField(Key = "custompage", Location = PersistLocation.Session)]
protected DataSet ds;
[PersistField(Location = PersistLocation.ViewState)]
protected bool isLoaded = false;
.
.
.
private void Page_Load(object sender, EventArgs e)
{
if (ds == null)
ds = new DataSet();
}
}
How does it work?When a new instance of your Page Handler (the class directly derived from your code-behind class) is created, its constructor is called. Just before it runs, the inline assignments you wrote are executed. Our If your attribute isn't in the persistent collection (such as when the page is first run), it's simply not assigned. That's when your inline assignments come in handy: to specify a default value for the field. After the execution of our loading overrides, you're ready to perform your work. Use the fields just like they were usual fields. When the page unloads, the other overrides will store the field value in the persistent collection. And you're done! Some Warnings
ConclusionI hope this article can be as useful for other developers as it's for me. Thank you. History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||