Friday, July 29, 2011

Optimizing use of page persisted properties by using session variables and local pointers

You have a variable that needs to be persisted between postbacks. How do you do this?
Your first instinct might be to use static variables. This is WRONG!

I am maintaining (and fixing lots of bugs) a website where I discovered that almost every page had a big bug in it. The following is what's wrong:

In Page class
protected static Account acct = new Account();

The problem is when multiple people are currently on this page, when Person1 sets fields in acct, it's going to change Person2's acct field too. This is because it's declared as static, which means it's shared between all instances of the page class!

So how do you handle this? Simple, use the Session variable like this:

//First create a const string that represents the location in Session
private const string SESSION_ACCT = "PAGENAME_ACCT";
//Now create a property that looks in the Session and creates a new object if it's
//not found
protected Account part
{
get
{
Account ad = null;
if (Session[SESSION_ACCT] == null)
{
ad = new Account();
Session[SESSION_ACCT] = ad;
}
else
ad = (Account)Session[SESSION_ACCT];
return ad;
}
set
{
Session[SESSION_ACCT] = value;
}

}

You will most likely want to populate the acct variable during page load. This is assuming you're pulling the account id out of QueryString and that you have a data access layer class called AccountDB with the method Account GetAccount(Guid AcctId).

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
acct = AccountDB.GetAccount(new Guid(Request.QueryString["id"]));
}
}

This is simply going to the acct property's set method. So it's going to do Session[SESSION_ACT] = AccountDB.GetAccount(new Guid(Request.QueryString["id"]));

Here's how you use acct

public void showAccountDetails()
{
Account localAcct = acct;
txtName.Text = localAcct.Name;
txtCreated.Text = localAcct.Created;
}

Why did I use Account localAcct instead of just using acct? This is because using acct means calling the getter everytime. So the above code would make two calls to the getter, meaning it runs through this code twice:
get
{
Account ad = null;
if (Session[SESSION_ACCT] == null)
{
ad = new Account();
Session[SESSION_ACCT] = ad;
}
else
ad = (Account)Session[SESSION_ACCT];
return ad;
}
This is alot more expensive than just creating a local pointer and directly accessing the fields. Every time it calls the getter it's going to be pulling out of Session and converting to Account. Whereas creating Account localAcct means you're storing the result of acct's getter in a local pointer and then directly accessing its fields.

No comments:

Post a Comment

There was an error in this gadget