|
|
Making life easier in ASP.NET | | Before I start, I'm going to make a confession. When it comes to ASP.NET, I've probably made every single bad mistake that someone can make. And although the code worked, I look back at some of the things I did in the past and wish I could XCOPY right over it and purge any trace of it from Source Safe. But more than anything else, I wrote a lot of inefficient code and wrote the same stuff over and over again - I guess I thought I was still in ASP land. Anyway, let me walk you through a few things that can make life a lot easier for you.
The first thing I think I really goofed up bad was not realizing how to implement Session State within my classes. What I mean was, I would create a regular class, with all of the get/set accessors like you normally would, and use the class variables to set session variables. Why? Well, because you couldn't use Session state within your classes - or so I thought.
The next thing I did was hard code my session variable names. Not a real big issue per se, but I wasted a lot of time flipping back and forth between pages to see exactly how I named one variable so I could use it again.
The third thing I did wrong was misuse inheritance. Too often I ended up writing the code that did almost the exact same stuff as the base class and instead of redesigning my base classes correctly, I just trucked on ahead with the derived classes.
So let's look at a few ways to deal with some of these problems. First, it's a good idea to not only group your projects in a logical order within a solution, but organize your folder structure as well. Now, people can argue for hours on end how to best organize your solution and project - I won't touch that issue. What matters is that you figure out what works for you and BE CONSISTENT about it. In my experience, I've found that no matter how complex, goofy, bizarre, unintuitive or whatever you organize things - as long as you are very consistent about it, it won't be that big of an impediment because you can count on certain things being true all of the time. So for this project, which doesn't have any real logic in it - I just created one project and three folders underneath it - BasePages, Constants and UIPages:

Now in a real project, things get much more complex, so for instance, I'd normally have a folder for all of my style sheets, XSLT transforms, images. Then I'd group things into logical areas like UI, Administration etc. Another common one is all of the javascript associated with a given area, like Menus. In another project I'd have my Business Interfaces, then one with my Business Objects, DALC Interfaces, DALC Objects, Custom Controls etc.
Ok, let's get down to business. If you add a simple class in your project and try to reference a Session variable, it won't compile. This actually makes sense right? After all, how does a DALC class that may run in multiple contexts, know that it is being used by an ASP.NET Application or Web Service and then figure it what Session is? It can't. However, by adding a class to your project that Inherits from System.Web.UI.Page, you know have a fully functioning web page - although if you added it as a class instead of a web form, you won't have visual support for it. Since we're not grabbing UI elements from the base page, this is actually a good thing. Now, the key here is to use the Session Variables in lieu of the private module level variables you normally use with your get/set accessors. Understand that the world is your's here. If you want to run a Crypto routine here - have at it. If you don't want to use session variables, fine (although if you are sharing these properties among descendants than you are defeating some of the purpose). A very simple implementation is shown below:
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using KDN.Samples.Constants;
namespace KDN.Samples.BasePages
{
/// <summary>
/// Summary description for KDNBasePage.
///
public class KDNBasePage : System.Web.UI.Page
{
public KDNBasePage(){}
#region Public Properties
public System.String UserName
{
get {
return Session[Constants.UIConstants.UserInfo.UserName];
}
set {
Session[Constants.UIConstants.UserInfo.UserName] = value;
}
}
public System.String EncryptedPassword
{
get {
return Session[Constants.UIConstants.UserInfo.EncryptedPassword];
}
set {
Session[Constants.UIConstants.UserInfo.EncryptedPassword] = value;
}
}
#endregion
}
}
|
Now, for each UI Page that I now build, I simply inherit from KDN.Samples.BasePages.KDNBasePage instead of System.Web.UI.Page. Now, it's common to have base pages that are related to certain modules, so my notion of a KDNBasePage is probably a big vague to directly inherit from in most base pages. Typically, you'd have the stuff that's common to every page here, and then derive classes from there that are common to areas of functionality and derive your UI pages from them. It's hard to really discuss the 'right' way here without getting into the bowels of OOP, and 'right' in an OOP sense depends a lot on what you are trying to accomplish.
One more thing before I go on - and this is an OOP issue more than an ASP.NET one, but deserves to be mentioned. I would probably never code a real class exactly like I did above. Why? Because if my Session variables were null, then I'd return a null value and cause all sorts of potential problems. First, I'd check to ensure it wasn't null and if it was, set it to something that would let me know it's null. Or I'd retrieve it. In practice, it's not uncommon for me to have 15-30 line accessors including exception trapping and logging - but that's totally dependent on your needs.
So now, you can access properties of the base class like this:
public class WebForm1 : KDN.Samples.BasePages.KDNBasePage
{
protected System.Web.UI.WebControls.TextBox tbUserName;
protected System.Web.UI.WebControls.TextBox tbPassword;
private void Page_Load(object sender, System.EventArgs e)
{
tbUserName.Text= base.UserName;
tbPassword.Text = base.EncryptedPassword;
}
} |
Now, think about this if you are new to the company or taking over the project. By typing in base, Intellisense will prompt you for the values. You don't have to even think about what the session variable name maps back to the UserName session variable. If you are encrypting and/or decrypting a password- you don't have to know anything about calling my crypto classes. Now, let's say we did it the old fashion way. You'd need to find the session variables (if they even existed), find the crypto library, and then call off them yourself. That alone would probably take 30 minutes minimum to find if this wasn't such a trivial example. This is what the OOP Notion of encapsulating is all about. It's not just about moving code out of the UI element - it's about making your objects usable without the user having to understand the nuances of your objects. I've been very guilty of this sin in the past - and often created classes just to get the code off of the form. But you'd have to still look at my classes to understand how to use them or if they even existed in the first place. By using inheritance this way - you'll make life a lot easier for yourself and others - and reduce the chances of bugs or ALMOST AS BAD - having a developer write the same code again b/c they didn't know it was there.
As far as the Constants class referenced above - there are many ways to get to the same place. .NET Sessions is a WONDERFUL tool to help you clean up code that's already been hard coded. And you can use it to build the same functionality that I'm about to discuss. Take a look at my Constants class:
namespace KDN.Samples.Constants
{
/// <summary>
/// Summary description for UIConstants.
///
public class UIConstants
{
public UIConstants(){//Read values from web.config or perform
//typical initialization functionality
}
public class UserInfo
{
public const String UserName = "userName";
public const String EncryptedPassword = "password";
public const String DomainId = "domainId";
public const String SessionStart = "sessionStart";
}
}
} |
Now, without the user knowing a thing about the session variables, they can use Intellisense to find out what I have defined as a constant. They don't have to worry about spelling it or anything and more importantly, they can determine what's there and what isn't by simply scrolling. If I comment these correctly, they'll even get important information describing what these are. So even if you think this is over complicating things - I ask you - if you were brand new to a company, wouldn't you appreciate such conveniences as opposed to having to dig through 300 page specs, assuming you even knew where to find the spec?
Finally, since you are hiding the implementation from the user, you can check if a given session variable is null and grab it from - a database, a web service, a web.config file or whatever else- it doesn't really matter to the guy using your class, all he knows is that it's there for him. Another thing is that you can handle all sorts of stuff for the user - like clearing session variables for them, custom events etc. If you take some time and construct some well thought out base pages, you can really save yourself and others a lot of time - and more importantly, you can reduce the possibility of bugs b/c typos for instance, won't be an issue. The IDE will catch them for you.
With this example, I've shown you how to go about accomplishing quite a bit. I've barely touched the surface of what you can do with these techniques, but that's the beauty of it, there's really no upper bound.
If you're going to do much in ASP.NET, I think the next things you need to look at are Cascading Style Sheets, XSLT Transforms (my new found love), HTTPHandlers and custom controls. CSS is probably the most important although the most boring of the bunch IMHO. However between CSS and Custom controls, you have a tremendous toolset to build flexible UI's that provide a consitent look and feel. Hopefully if I get some time I'll have more on each of these.
Further Reading:
Underpinnings of the Session State Implementation in ASP.NET
ASP.NET Session State FAQ
|
|