Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using a Custom Base Class for Security and Session Management

0.00/5 (No votes)
21 Jun 2008 1  
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

    /// <summary>
    /// Each page should "know" its name
    /// </summary>
    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



    /// <summary>
    /// 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
    /// </summary>
    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
    {
    /// <summary>
    /// Summary description for Utils.Debugger
    /// </summary>
    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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here