Click here to Skip to main content
Click here to Skip to main content

Using a Custom Base Class for Security and Session Management

, 21 Jun 2008
Rate this:
Please Sign up or sign in to vote.
Using a custom base class for security and Session management.

Introduction

One of the requirements of the project I work on is that, "the admin should be able to mark a user as inactive, so the user would not be able to access the application anymore even if he is currently logged in". First, I thought that this would not be possible, but later on, I found this graat article by Robert Boedigheimer, which suggested the use of a custom base class, which brought to me an entire new horizon on how to tackle the two most important parts of writing .NET web based applications - security and memory management.

Using the code

Derive your page from the base class. In the code-behind file, use:

public partial class MyImportantPage : CustomBasePage

Thus, your pages will have all the properties of the System.Web.UI.Page class plus those you have defined in your base class. The second advantage of this class is Session management. Let us assume that you have 1 GB of RAM on your Web server. What would happen if you retrieve a couple of datasets per page (1 MB each)? Your Session expiration time is 30 minutes and the number of on-line users is close to 600 ... Well, with those simulated numbers, with the default settings, the IIS will perform a memory cleaning and throw all the users out ...

In reality, most of the variables set as Session variables do not need to be global, but are page-specific... Somebody might argue to use ViewState for those variables - well, watch the performance after setting a dataset with a 1 MB size ... the ViewState should only be used for small variables. Another option is to use the Cache ... My experience is that the Cache is unreliable - you cannot be 100% sure what the client browser will do to your important objects stored, yet your code rules the server ...

When you would like to set a variable which is to be used globally (e.g., the variable will persist through the time of the current session of the user, even if the user leaves the current page), set the variable like so:

string StrGlobalVariable = Session [ "global.StrGlobalVariable" ];

When you would like to use a variable only in the scope of the page (e.g., the variable will be deleted once the user requests a different page), set the variable as follows:

string StrPageVariable = Session [ base.PageName + ".PageVariable" ] ;

So, here is the code (read the comments carefully):

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Collections.Generic;
using System.Text;

//SOURCE:http://aspalliance.com/63
//AUTHOR:Robert Boedigheimer
//page life cycle http://msdn.microsoft.com/en-us/library/ms178472.aspx

public class CustomBasePage : System.Web.UI.Page
{
 private string pageName;
#region Properties

    /// <span class="code-SummaryComment"><summary></span>
    /// Each page should "know" its name
    /// <span class="code-SummaryComment"></summary></span>
    public string PageName
    {
        get
        {
            return System.IO.Path.GetFileNameWithoutExtension (
                   System.Web.HttpContext.Current.Request.Url.AbsolutePath );
        } //eof get
        set { pageName = value; } //eof set
    } //eof property MyPageName

    #endregion //Properties


  public CustomBasePage ()
  {
  }

  override protected void OnInit ( EventArgs e )
  {
   base.OnInit ( e );
   #region Introduction
   string msg;
   string baseDir;
   string pageName;
  #endregion //Introduction


 #region Instantiation
  pageName = System.IO.Path.GetFileNameWithoutExtension (
             System.Web.HttpContext.Current.Request.Url.AbsolutePath );

//Utils.Debugger.WriteIf ( pageName + "            OnInit --- Start " );
//ucomment this to debug each page after the login
        //Utils.Debugger.DebugPage ( this.Page );

        
        if (HttpContext.Current.Session != null)
        {

            //Tested and the IsNewSession is more advanced then simply checking if 
            // a cookie is present, it does take into account a session timeout, because 
            // I tested a timeout and it did show as a new session
            if (HttpContext.Current.Session.IsNewSession)
            {
                // If it says it is a new session,
                // but an existing cookie exists, then it must 
                // have timed out (can't use the cookie
                // collection because even on first 
                // request it already contains the cookie (request and response
                // seem to share the collection)
                string szCookieHeader = Request.Headers [ "Cookie" ];
                if (( null != szCookieHeader ) &&
                ( szCookieHeader.IndexOf ( "ASP.NET_SessionId" ) >= 0 ))
                {
                    HttpContext.Current.Session [ "global.msg" ] = 
                        " No action has been performed in " + 
                        "the last 15 minutes, please login again";
                    Response.Redirect ( "~/login.aspx" );
                }
            } //eof if (HttpContext.Current.Session.IsNewSession)
        } //eof is Session is not null 



        //comm - if this is not the login page AND 
        if (Session [ "global.LOGINISOK" ] == null || 
            System.Convert.ToString ( 
            Session [ "global.LOGINISOK" ] ).Equals ( "LOGINISOK" ) == false)
        {
            Utils.Debugger.WriteIf ( Session [ "global.Domain_Name" ] + 
            " redirecting to login page !!!: \n" );
            Session [ "global.msg" ]  = 
            "Welcome to the My Application name ! Please, login first ";
            Response.Redirect ( "~/login.aspx" );

        }
        else   //comm --   
        {
            //comm - clear all session variables , 
            //but the global ones and the ones belonging to this page
    ClearAllNonGlobalSessionsButMine ();
        }
    } //eof OnInit



    /// <span class="code-SummaryComment"><summary></span>
    /// This method relies on the convention practice that the Session keys
    /// would be named as follows:
    /// pageName.variableName - if the Session variable is page specific and 
    /// global.variableName - if the Session variable should be trully global
    /// <span class="code-SummaryComment"></summary></span>
    private void ClearAllNonGlobalSessionsButMine ()
    {
        string fileNameNoExt = System.IO.Path.GetFileNameWithoutExtension (
                 System.Web.HttpContext.Current.Request.Url.AbsolutePath );

        for (int i = 0; i< HttpContext.Current.Session.Count; i++)
        {
            string keyValue = HttpContext.Current.Session.Keys [ i ];
            if (keyValue.Contains ( fileNameNoExt ) || keyValue.Contains ( "global" ))
            { ; }        //do nothing = preserve the value in the session 
            else
            {
              //answers the question: what session
              //variables are deleted during page change
              HttpContext.Current.Session [ HttpContext.Current.Session.Keys [ i ] ] = null;
            } //eof else if it is global or belongs to current page
        } //eof loop 

    } //eof public static void ClearAllButCurrent (string pageName )  

public void ClearAllNonGlobalSessionsAndMine ()
{
string fileNameNoExt = System.IO.Path.GetFileNameWithoutExtension (
                                System.Web.HttpContext.Current.Request.Url.AbsolutePath );

  for (int i = 0; i< HttpContext.Current.Session.Count; i++)
  {
  string keyValue = HttpContext.Current.Session.Keys [ i ];
  if (keyValue.Contains ( "global" ))
  { ; }  //do nothing = preserve the value in the session 
  else
  {
  //answers the question: what session variables are deleted during page change
  HttpContext.Current.Session [ HttpContext.Current.Session.Keys [ i ] ] = null;
} //eof else if it is global or belongs to current page
} //eof loop 

} //eof public static void ClearAllButCurrent (string pageName )  


} //eof BasePageClass

I almost noticed, you wandered what the DebugPage method is. Here it is:

using System;
using System.Text.RegularExpressions;
using System.Data;
using System.Web.UI.WebControls;

namespace Utils
    {
    /// <span class="code-SummaryComment"><summary></span>
    /// Summary description for Utils.Debugger
    /// <span class="code-SummaryComment"></summary></span>
    public class Debugger

public static void DebugPage ( System.Web.UI.Page page )
{

string baseDirLocal = System.Web.HttpContext.Current.Server.MapPath ( "~" );
Regex Remover = new Regex ( @"^.*(\\|\/)(.*)$",
RegexOptions.IgnoreCase | RegexOptions.Compiled );
string bareDir = Remover.Replace (  baseDirLocal , "$2" );


string strToRemoveAtEnd= System.Web.HttpContext.Current.Request.Url.AbsolutePath;
char [] charsToRemoveAtEnd = strToRemoveAtEnd.ToCharArray ();
string baseDir = System.Web.HttpContext.Current.Request.Url.AbsoluteUri;
baseDir = baseDir.TrimEnd ( charsToRemoveAtEnd );
baseDir = baseDir + "/" + bareDir + "/";



WriteIf("The basedir of the project locally is " +  
        "HttpContext.Current.Server.MapPath(\"~/\");" +
        System.Web.HttpContext.Current.Server.MapPath ( "~" ) );

WriteIf ( "The basedir of the project locally is " + 
          "AppDomain.CurrentDomain.BaseDirectory;" + 
          AppDomain.CurrentDomain.BaseDirectory);

WriteIf ( "The virtual path of this page " + 
          "( System.Web.HttpContext.Current.Request.PathInfo) is " + 
          System.Web.HttpContext.Current.Request.PathInfo ) ;

WriteIf ( "System.IO.Path.GetFileName (" + 
          " System.Web.HttpContext.Current.Request.Url.AbsolutePath ) -- " + 
          System.IO.Path.GetFileName ( 
          System.Web.HttpContext.Current.Request.Url.AbsolutePath ) );
WriteIf ( "System.Web.HttpContext.Current.Request.Url.AbsolutePath -- " + 
          System.Web.HttpContext.Current.Request.Url.AbsolutePath );
WriteIf ( "System.Web.HttpContext.Current.Request.Url.AbsoluteUri -- " + 
          System.Web.HttpContext.Current.Request.Url.AbsoluteUri );
WriteIf ( "System.Web.HttpContext.Current.Request.Url.DnsSafeHost -- " + 
          System.Web.HttpContext.Current.Request.Url.DnsSafeHost );
WriteIf ( "System.Web.HttpContext.Current.Request.Url.Fragment -- " + 
          System.Web.HttpContext.Current.Request.Url.Fragment );
WriteIf ( "System.Web.HttpContext.Current.Request.Url.Host -- " + 
          System.Web.HttpContext.Current.Request.Url.Host ) ; 
WriteIf ( "System.Web.HttpContext.Current.Request.Url.HostNameType -- " + 
          System.Web.HttpContext.Current.Request.Url.HostNameType ) ;
WriteIf ( "System.Web.HttpContext.Current.Request.Url.LocalPath -- " + 
          System.Web.HttpContext.Current.Request.Url.LocalPath ) ;
WriteIf ( "System.Web.HttpContext.Current.Request.Url.OriginalString -- " + 
          System.Web.HttpContext.Current.Request.Url.OriginalString ) ;
WriteIf ( "System.Web.HttpContext.Current.Request.Url.PathAndQuery -- " + 
          System.Web.HttpContext.Current.Request.Url.PathAndQuery ) ;
WriteIf ( "System.Web.HttpContext.Current.Request.Url.Scheme -- " + 
          System.Web.HttpContext.Current.Request.Url.Scheme ) ;
WriteIf ( "System.Web.HttpContext.Current.Request.Url.Segments.ToString () -- " + 
          System.Web.HttpContext.Current.Request.Url.Segments.ToString () );
WriteIf ( "System.Web.HttpContext.Current.Request.Url.UserInfo -- " + 
          System.Web.HttpContext.Current.Request.Url.UserInfo );
WriteIf ( "System.Web.HttpContext.Current.Request.ServerVariables[ \"HTTP_COOKIE\" ] is " + 
          System.Web.HttpContext.Current.Request.ServerVariables [ "HTTP_COOKIE" ] );

} //eof DebugPage

        public static void WriteIf ( string msg )
        {
  System.Diagnostics.Debug.WriteIf ( System.Convert.ToBoolean
    ( System.Configuration.ConfigurationSettings.AppSettings [ "Debugging" ] ) ,
  DateTime.Now.ToString ( "yyyy:MM:dd -- hh:mm:ss.fff --- " ) + msg + "\n" );
        }
} //eof class Debugger 
} //eof namespace  Utils

Points of interest

If you have carefully read the code, now you know where to put your code for implementing the requirement I presented above. If you are still having difficulties figuring out, put a comment below, and I will spare more time for writing an article about it ...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

yordan_georgiev
Web Developer Oxit Oy
Finland Finland
I work in OXIT - a small IT consulting company, which has participated in the building of the most sophisticated IT Systems for several big Finnish and international companies (including Fortune 500 members) and continues to provide highly sophisticated IT Solutions to its customers.
 
I enjoy designing and implementing software or small scripts in different programming languages.
 
I am fascinated by the magic of software, which has the power to change the world.

Comments and Discussions

 
GeneralThank You (and one small request) PinmemberforCryingOutLoud21-May-09 11:10 
GeneralRe: Thank You (and one small request) Pinmemberyordan_georgiev21-May-09 14:30 
GeneralMethod for testing for timed out session is incomplete Pinmemberccady19-Nov-08 9:55 
GeneralRe: Method for testing for timed out session is incomplete Pinmemberyordan_georgiev20-Nov-08 1:31 
Generalmultiple tabs Pinmemberdbwinger23-Jun-08 2:20 
GeneralRe: multiple tabs PinmemberMike Ellison23-Jun-08 3:07 
GeneralRe: multiple tabs Pinmemberdbwinger23-Jun-08 3:12 
GeneralRe: multiple tabs Pinmemberyordan_georgiev25-Jun-08 20:52 
GeneralRe: multiple tabs Pinmemberdbwinger26-Jun-08 2:13 
GeneralRe: multiple tabs [modified] Pinmemberyordan_georgiev23-Jun-08 7:58 
Hi,
 
You are absolutely correct. Usually for most of the users one tab is enough. In order to prevent this from happening there should be some JavaScript AJAX solution, I 've read once something about ... but never bothered to implement it ... if a more clever person knows how ... let him speak Wink | ;)
 
Anyway I quess JavaScript , AJAX cookie reader , which "knows" the current page and "knows" the current session id should pass the info to this BaseClass ... - this might be the first shooting in the dark for a beginning ...
 
modified on Thursday, May 21, 2009 8:32 PM

GeneralRe: multiple tabs Pinmemberstar6522569223-Jun-08 23:57 
GeneralA different type of though. PinmemberRajib Ahmed22-Jun-08 6:28 
QuestionHow about an HttpModule? PinmemberMike Ellison22-Jun-08 4:56 
AnswerRe: How about an HttpModule? [modified] Pinmemberyordan_georgiev22-Jun-08 19:59 
GeneralRe: How about an HttpModule? PinmemberMike Ellison23-Jun-08 3:11 
GeneralRe: How about an HttpModule? Pinmemberyordan_georgiev23-Jun-08 20:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 21 Jun 2008
Article Copyright 2008 by yordan_georgiev
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid