Introduction
This article gives some very basic approach for designing a scalable, maintainable and extensible web application using ASP.NET and OOP approach.
Defining the Base Classes for the Application
It's very common to have a mixture of web pages in the application with some requiring proper user authentication to access the page and others may be accessible without proper authentication. And also with more applications getting complex there may be requirement to have different levels of access to different part of the application based on the user authentication level.
The following code sample illustrates how we can approach designing the web application using OOP to make the application more scalable and maintainable. In this example consider a simple web project with only one application. As said before we can have a mixture of both secured web pages (needs user authentication to access the page) and Non Secured Web pages (can be accessed with out user authentication). We can approach this by defining two base classes both inheriting from System.Web.UI.Page as shown below.
public class SecuredWebPage: System.Web.UI.Page
{
public SecuredWebPage()
{}
public void OnInit( System.Web.UI.Page Page)
{
if (Page.Session["CustomSession"] == null)
{
Page.Response.Redirect ("LogOn.aspx?CallingPage=" + Request.RawUrl );
}
}
}
public class NonSecuredWebPage: System.Web.UI.Page
{
public NonSecuredWebPage()
{}
public void OnInit(System.Web.UI.Page Page)
{
if (Page.Session["GenericSession"] == null)
{
GenericSession genericSession = new GenericSession();
genericSession.User = "Ananymous";
Page.Session["GenericSession"] = genericSession;
}
}
These two base classes have the init event which is invoked from the Pages that are used in the application passing the page itself as the argument. All we do here is check for if there is valid Session Object available in the Page. (For the Non Secured pages it's not necessary to check any Session or we can set some Generic Session that might be useful while navigating the application. The Session object mentioned in the code above can be defined as the class below.
Defining the Session Class:
public class CustomSession
{
private string mstrUser = "";
private string mstrPassword = "";
public CustomSession()
{}
public string User
{
get{ return mstrUser;}
set {mstrUser = value;}
}
public string Password
{
get {return mstrPassword;}
set {mstrPassword = value;}
}
}
public class GenericSession
{
private string mstrUser = "";
public string User
{
get{ return mstrUser;}
set {mstrUser = value;}
}
}
The Session class as defined above will be more flexible, scalable and maintainable rather than defining the Session for each properties defined in the class. By having the whole class in the Session the various properties of the Session can be accessed from the page as
customSession = (CustomSession) Session["CustomSession"];
The above Base classes along with the Session class checks for the valid Session object and if not available then redirect to a page called LogOnpage.aspx with QueryString of the URL that is calling this page. This can be used to redirect to that page after successful log on from the Log on Page. (Other wise we can redirect to the default page on the application as per the business need). In this example we are redirecting the page to the page that called this Log On page.
public class LogOn : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
private void btnOk_Click(object sender, System.EventArgs e)
{
//Validate and Authenticate the User credentials here..
CustomSession customSession = new CustomSession();
customSession.User = txtUser.Text;
customSession.Password = txtPassword.Text;
Session["CustomSession"] = customSession;
Response.Redirect (strUrl);
this.RegisterStartupScript ("MyFunction","<script language='javascript'>window.returnValue = 'OK';window.close();</script>");
}
}
}
Defining the Web pages in the application:
With these base classes in place now all our pages in the application can be derived from either the SecuredWebPage class or the NonSecuredWebPage class with the authentication to the page implemented by default through these base classes. So the actual authentication need not to be included in each page. And if any changes in the authentication or the Session that need's to be changed the change can be done in one place with minimum code change and less chance of introducing any new bugs.
The code sample for the two types of pages in the application is as follows:
public class WebForm1 : Ez.SecuredWebpage
{
private void Page_Load(object sender, System.EventArgs e)
{
CustomSession customSession = (CustomSession) Session["CustomSession"];
Response.Write ("The Page is logged on with User - ");
Response.Write(customSession.User);
Response.Write ("<BR>");
Response.Write ("and the password is ");
Response.Write (customSession.Password);
}
override protected void OnInit(EventArgs e)
{
base.OnInit(this);
}
}
public class WebForm3 : Ez.NonSecuredWebPage
{
private void Page_Load(object sender, System.EventArgs e)
{
GenericSession genericSession = (GenericSession) Session["GenericSession"];
Response.Write ("The Page is a non secured page logged on with User - ");
Response.Write(genericSession.User);
}
override protected void OnInit(EventArgs e)
{
base.OnInit(this);
}
}
This above approach can be practiced as a Template while designing a web application.
Expanding the design scope across many applications
Most of the application in real world is not going to be as simple as the sample application presented above. There may be lots of applications in the project and each with different levels of authentication level for a user. When the project gets more complicated it will be a good practice to have the base classes and the log on project defined under a folder called (for ex) Common and make that referenced to all the applications that are in the project group. And it will be a good practice to have the UI and the Data /Utility Access Layer under different folders in the a project. For example we can have a project called Project1 and have two folders inside that as ProjectUI where all the web pages will be residing and ProjectMI folder where we can have all the Utility access / Data Access done there. This will be a good practice to follow and easy to maintain the code in the long run. And also by having the MI folder for each application the above explained base class inheritance can be further extended by defining a base class for each folder which in turn is derived from the Common Base class. By doing so we can set the Attributes for the base class in the MI folder and then call the Common with those attributes. This way we will be able to Set or Retrieve the Session object accordingly as per the application.
Last but not the least while designing the complex application it will be always a good practice to have the sub folder properly defined and grouping the classes accordingly. For example we should have a Utility Folder in the application which can have many classes to handle all the I/O or Registry operations etc.. by having classes like Fileutiltiy.cs and RegistryUtility.cs etc.. And also a Data class from where the Data Access operations should be handled. The Page should always access it's corresponding MI Class in the sub folder which in turn will access the Common / Utility / Data Access Layers. Defining and Organizing the folders and files in the project will in most cases decide how the project can be scaled or maintained as the business requirement grows.
The above approach is an effort to define a scalable, maintainable web application development implementing OOP. Depending on the need this approach can be modularized more and developing the complex web applications can be achieved with little less effort.
Conclusion
I hope the above explained approach will help a lot of developers who are in the initial phase of designing and developing either a simple or complex web applications and help develop the application more effectively.