Programatically Loading Providers by Avoiding web / app config

Background
Recently I was in a situation where I had to expose two of my .NET Libraries as COM, to invoke via VBScript (Late Binding) from one of the Legacy Application. One of the .NET Library uses .NetTiers and the other one uses Subsonic as the DAL, so as you can understand all the configurations are declared in the app.config / web.config file as something like this:

Nettiers Config
<netTiersService defaultProvider=”SqlNetTiersProvider”>
  <providers>   
    <add
name=”SqlNetTiersProvider”
type=”Locum.Net.Data.SqlClient.SqlNetTiersProvider, Locum.Net.Data.SqlClient”
connectionStringName=”netTiersConnectionString”
providerInvariantName=”System.Data.SqlClient”
entityFactoryType=”Locum.Net.Entities.EntityFactory”
useEntityFactory=”true”
enableEntityTracking=”false”
enableMethodAuthorization=”false”
useStoredProcedure=”false”
  />   
  </providers>
</netTiersService>

Subsonic Config
<SubSonicService  defaultProvider="Northwind">
  <providers>
    <clear/>
    <add 
      name="Northwind" 
      type="SubSonic.SqlDataProvider, 
      SubSonic" connectionStringName="Northwind"
      generatedNamespace="Northwind"/>
  </providers>
</SubSonicService>
 
Investigation 

I started playing with it.
Step1: I wrote my special layer (library) on top of my .Net (BLL) Business Logic Layer, 
which will expose only the necessary methods for COM. This is important as we can keep the
exposure clean by using the special COM related Attributes. Example:
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IStudentMessageContextClass
{...}

[ClassInterface(ClassInterfaceType.None)]
public class StudentMessageContextClass : IStudentMessageContextClass
{…}













Step2: I made my .Net ClassLibrary Com visible.
*VS2005 right click the ClassLibrary Project and click Properties.
*In the Application Tab click "Assembly Information" Button.
*Check the "Make Assembly COM Visible" checkbox.

Step3: Used RegAsm to register it in VS Command Prompt.
>regasm filename.dll /tlb filename.tlb /codebase filepath
remember to add the codebase with the path of dll.
Step4: Started writing the VB Class to test if its working. Soon the fun begins and
I realised that the configs has to be provided to load the correct provider details etc.
As I do not know which application will be calling my Libraries and as I do not have,
any controls on them I thought lets pass the configs programatically.



Step5: Initially I tried to pass the providers programatically by extending the NetTiersServiceSection class 
and allowing to set the property. (Note: I did similiar with SubSonicSection)

public class ExtendedNetTiersServiceSection : NetTiersServiceSection
{
  [ConfigurationProperty(“providers”)]
  public new ProviderSettingsCollection Providers
  {
    get { return (ProviderSettingsCollection)base[“providers”]; }
    set { base[“providers”] = value; }
  }
}

 

//Create an instance of the extended section
ExtendedNetTiersServiceSection section = new ExtendedNetTiersServiceSection();
ProviderSettingsCollection providers = new ProviderSettingsCollection();
ProviderSettings provider = new ProviderSettings(“SqlNetTiersProvider”, “Sms.Net.Data.SqlClient.SqlNetTiersProvider, Sms.Net.Data.SqlClient”);

//Pass the parameters that we normally put in the web/app config file
provider.Parameters.Add(“useStoredProcedure”, “false”);
provider.Parameters.Add(“connectionString”, “YourConnectionString”);

…//other parameters as necessary

providers.Add(provider);
section.Providers = providers;
DataRepository.NetTiersSection = section;

It was all good but I soon realized that the Sms.Net.Data.SqlClient.dll needs
to be in the same folder of the host application else it comes back with error,
Sms.Net.Data.SqlClient.dll could not be found/loaded or one of its dependencies
could not be loaded.
The reason is it will try to instantiate the provider using
System.Web.Configuration.ProvidersHelper.InstantiateProviders(NetTiersSection.Providers, _providers, typeof(NetTiersProvider));
and it will look for the dlls at the same path of the host application.
Step6: So the above solution did not work for me and I scraped Step5, as I mentioned earlier that I do not know 
who will be calling my dlls, and I do not want to force a requirement that my dlls
should be in the same folder. But its a workable solution too...also by this time you might
be asking why I am not writing a Webservice and ask the Legacy Application to consume that...
don't ask me why but I can't do it....its defined as part of the project requirement
that I cannot have a webservice....:(
Step7: So I looked further in to the API and discovered its not that difficult as I thought, 
the (.NetTiers) DataRepository class comes with LoadProvider() function and (Subsonic) comes
with AddProvider method in the DataService class where I can easily pass my providers programmatically.



.Nettiers DataRepository class
public static void LoadProvider(NetTiersProvider provider, bool setAsDefault)
{
....
}
Subsonic DataService class

public static void AddProvider(DataProvider provider)
{
}


But soon I also realised that there is no way to pass a Name of a provider
as the Name property is Readonly.

public virtual string Name { get; }
So the trick is to use the Initialize method 
of the providers that implements abstract class System.Configuration.Provider.ProviderBase.
public virtual void Initialize(string name, NameValueCollection config);
So to replicate the Nettiers config section that I mentioned above at the starting 
of this article, I finally wrote the following block of code.

//Instantiate the provider
NetTiersProvider provider = new SqlNetTiersProvider();
//Pass all the parameters of the provider here
NameValueCollection config = new NameValueCollection();
config.Add(“useStoredProcedure”, “false”);
config.Add(“connectionString”, “YourConnectionString”);
config.Add(“connectionStringName”, “netTiersConnectionString”);
config.Add(“providerInvariantName”, “System.Data.SqlClient”);
config.Add(“useEntityFactory”, “true”);
config.Add(“enableEntityTracking”, “false”);
config.Add(“enableMethodAuthorization”, “false”);
//Initialize the provider with a proper name and config
provider.Initialize(“SqlNetTiersProvider”, config);
DataRepository.LoadProvider(provider, true);

 
And for SubSonic after initializing the correct provider with the correct parameters,
we can use SubSonic.DataService.AddProvider(DataProvider provider) method
to add a provider to the providers list. We have to also set the
SubSonic.DataService.Provider with the initialized provider so it assigns it as the default provider.

Conclusion
Here we have seen how we can load a provider programatically and avoid any dependencies on
web/app config. Here I have demonstrated with the providers of .NetTiers and SubSonic,
but its prettymuch the same for all other providers that implements System.Configuration.Provider.ProviderBase.
The trick is to use the Initialize method with correct NameValueCollection and a name
to instantiate a provider that implements the System.Configuration.Provider.ProviderBase.


Hope this helps.
 

Visual C# Development Settings

source: http://blogs.msdn.com/karenliu/archive/2006/06/12/628756.aspx

Visual C# Development Settings Default KeyBindings

Editing

Edit.CollapseToDefinitions

CTRL + M, O

Collapses existing regions to provide a high-level view of the types and members in the source file.

Edit.CommentSelection

CTRL + K, C or CTRL + E, C

Inserts // at the beginning of the current line or every line of the current selection.

Edit.FormatDocument

CTRL + K, D or CTRL + E, D

Formats the current document according to the indentation and code formatting settings specified on the Formatting pane under Tools | Options | Text Editor | C#.

Edit.FormatSelection

CTRL + K, F or CTRL + E, F

Formats the current selection according to the indentation and code formatting settings specified on the Formatting pane under Tools | Options | Text Editor | C#.

Edit.InsertSnippet

CTRL + K, X

Displays the Code Snippet Picker. The selected code snippet will be inserted at the cursor position.

Edit.StopOutlining

CTRL + M, P

Removes all outlining information from the whole document.

Edit.SurroundWith

CTRL + K, S

Displays the Code Snippet Picker. The selected code snippet will be wrapped around the selected text.

Edit.ToggleAllOutlining

CTRL + M, L

Toggles all previously collapsed outlining regions between collapsed and expanded states.

Expand Code Snippet

[TAB]

Expand Code Snippet

Edit.ToggleOutliningExpansion

CTRL + M, M

Toggles the currently selected collapsed region between the collapsed and expanded state.

Edit.UncommentSelection

CTRL + K, U or CTRL + E, U

Removes the // at the beginning of the current line or every line of the current selection.

Edit.CycleClipboardRing

CTRL + SHIFT + V

Pastes text from the Clipboard ring to the cursor location in the file. Subsequent use of the shortcut key iterates through the items in the Clipboard ring.

Edit.Replace

CTRL + H

Displays the replace options in the Quick tab of the Find and Replace dialog box.

Edit.ReplaceInFiles

CTRL + SHIFT + H

Displays the replace options on the In Files tab of the Find and Replace dialog box.

View.ShowSmartTag

CTRL + . or SHIFT + ALT + F10

Displays the available options on the smart tag menu.

Edit.InvokeSnippetFromShortcut

TAB

Inserts the expanded code snippet from the shortcut name.

File

File.NewProject

CTRL + SHIFT + N

Displays the New Project dialog box.

File.OpenProject

CTRL + SHIFT + O

Displays the Open Project dialog box, where existing projects can be added to the solution.

Project.AddClass

SHIFT + ALT + C

Displays the Add New Item dialog box and selects Class template as default.

Project.AddExistingItem

SHIFT + ALT + A

Displays the Add Existing Item dialog box, where existing files can be added to the current project.

Project.AddNewItem

CTRL + SHIFT + A

Displays the Add New Item dialog box, where a new file can be added to the current project.

Window.ShowEzMDIFileList

CTRL + ALT + DOWN ARROW

Displays a pop-up listing of all open documents.

Edit.OpenFile

CTRL + O

Displays the Open File dialog box where a file can be selected to be opened. This does not add the file to the project.

IntelliSense

Edit.CompleteWord

CTRL + SPACE or CTRL + K, W

Completes the current word in the completion list.

Edit.ListMembers

CTRL + J or CTRL + K, L

Invokes the IntelliSense completion list.

Edit.QuickInfo

CTRL + K, I

Displays the complete declaration for the specified identifier in your code in a Quick Info tool tip.

Edit.ParameterInfo

CTRL + SHIFT + SPACE or CTRL K, P

Displays the name, number and type of parameters required for the specified method.

Navigation

Edit.FindAllReferences

SHIFT + F12 or CTRL + K, R

Displays a list of all references for the symbol selected.

Edit.GoToBrace

CTRL + ]

Moves the cursor location to the matching brace in the source file.

Edit.GoToDefinition

F12

Navigates to the declaration for the selected symbol in code.

Edit.GoToNextLocation

F8

Moves the cursor to the next item, such as a task in the Task List window or a search match in the Find Results window. Subsequent invocations will move to the next item in the list.

Edit.IncrementalSearch

CTRL + I

Activates incremental search. If incremental search is on, but no input is passed, the previous search query is used. If search input has been found, next invocation searches for the next occurrence of the input text.

View.ClassViewGoToSearchCombo

CTRL + K, CTRL + V

Brings focus to the Class View search box.

View.ForwardBrowseContext

CTRL + SHIFT + 7

Moves to the next item called in code in the current file. Uses the Go To Definition navigation stack.

View.NavigateBackward

CTRL + MINUS SIGN (-)

Moves to the previously browsed line of code.

View.NavigateForward

CTRL + SHIFT + MINUS SIGN (-)

Moves to the next browsed line of code.

View.PopBrowseContext

CTRL + SHIFT + 8

Moves to the previous item called in code in the current file. Uses the Go To Definition navigation stack.

Edit.FindInFiles

CTRL + SHIFT + F

Displays the In Files tab of the Find and Replace dialog box.

Edit.FindSymbol

ALT + F12

Displays the Find Symbol pane of the Find and Replace dialog box.

View.ViewCode

F7

Displays the selected item in Code view of the editor.

View.ViewDesigner

SHIFT + F7

Switches to Design view for the current document. Available only in Source view.

View.ViewMarkup

SHIFT + F7

Switches to Source view for the current document. Available only in Design view.

Window.MoveToNavigationBar

CTRL + F2

Moves the cursor to the drop-down bar located at the top of the code editor when the editor is in Code view or Server Code view.

Edit.Find

CTRL + F

Displays the Quick tab of the Find and Replace dialog box.

Edit.GoTo

CTRL + G

Displays the Go To Line dialog box.

Edit.GoToFindCombo

CTRL + /

Puts the cursor in the Find/Command box on the Standard toolbar.

Refactoring

Refactor.EncapsulateField

CTRL + R, E

Displays the Encapsulate Field dialog box, which allows creation of a property from an existing field and updates all references to use the new property.

Refactor.ExtractInterface

CTRL + R, I

Displays the Extract Interface dialog box, which allows creation of a new interface with members derived from an existing class, struct, or interface.

Refactor.ExtractMethod

CTRL + R, M

Displays the Extract Method dialog box, which allows creation of a new method from the selected code.

Refactor.PromoteLocalVariabletoParameter

CTRL + R, P

Moves a variable from a local usage to a method, indexer, or constructor parameter and updates all call sites appropriately.

Refactor.RemoveParameters

CTRL + R, V

Displays the Remove Parameters dialog box, which allows removal of parameters from methods, indexers, or delegates by changing the declaration at any locations where the member is called.

Refactor.Rename

CTRL + R, R or F2

Displays the Rename dialog box, which allows renaming all references for an identifier.

Refactor.ReorderParameters

CTRL + R, O

Displays the Reorder Parameters dialog box, which allows changes to the order of the parameters for methods, indexers, and delegates.

Window

View.ClassView

CTRL + W, C

Displays the Class View window.

View.CodeDefinitionWindow

CTRL + W, D

Displays the Code Definition window.

View.CommandWindow

CTRL + W, A

Displays the Command window, where commands can be invoked to manipulate the integrated development environment (IDE).

View.ErrorList

CTRL + W, E

Displays the Error List window.

View.ObjectBrowser

CTRL + W, J

Displays the Object Browser.

View.Output

CTRL + W, O

Displays the Output window, where status messages can be viewed at run time.

View.PropertiesWindow

CTRL + W, P

Displays the Properties window, which lists the design-time properties and events for the currently selected item.

View.SolutionExplorer

CTRL + W, S

Displays Solution Explorer, which lists the projects and files in the current solution.

View.TaskList

CTRL + W, T

Displays the Task List window, which displays custom tasks, comments, shortcuts, warnings and error messages.

View.Toolbox

CTRL + W, X

Displays the Toolbox, which contains controls that can be included or used with your code.

View.ServerExplorer

CTRL + W, L

Displays Server Explorer, which lets you view and manipulate database servers, event logs, message queues, Web services, and other operating system services.

Window.CloseToolWindow

SHIFT + ESC

Closes the current tool window.

Data.ShowDataSources

SHIFT + ALT + D

Displays the Data Sources window.

Window.CloseDocumentWindow

CTRL + F4

Closes the current tab.

Window.NextDocumentWindowNav

CTRL + TAB

Displays the IDE Navigator, with the first document window selected.

Build

Build.BuildSolution

F6 or CTRL + SHIFT + B

Builds all the projects in the solution.

Build.BuildSelection

SHIFT + F6

Builds the selected project and its dependencies.

Debugging

Debug.Autos

CTRL + D, A

Displays the Autos window, which displays variables used in the current line of code and the preceding line of code.

Debug.CallStack

CTRL + D, C

Displays the Call Stack window, which displays a list of all active methods or stack frames for the current thread of execution.

Debug.Immediate

CTRL + D, I

Displays the Immediate window, where expressions can be evaluated.

Debug.Locals

CTRL + D, L

Displays the Locals window, which displays the local variables and their values for each method in the current stack frame.

Debug.QuickWatch

CTRL + D, Q

Displays the QuickWatch dialog box that has the current value of the selected expression.

Debug.Start

F5

Launches the application under the debugger based off of the settings from the startup project. When in Break mode, invoking this command will run the application until the next breakpoint.

Debug.StartWithoutDebugging

CTRL + F5

Launches the application without invoking the debugger.

Debug.StepInto

F11

Executes code one statement at a time, following execution into method calls.

Debug.StepOut

SHIFT + F11

Executes the remaining lines of a method in which the current execution point is located.

Debug.StepOver

F10

Executes the next line of code, but does not follow execution through any method calls.

Debug.StopDebugging

SHIFT + F5

Stops running the current application under the debugger.

Debug.ToggleBreakpoint

F9

Sets or removes a breakpoint at the current line.

Debug.Watch

CTRL + D, W

Displays the Watch window, which displays the values of selected variables or watch expressions.

Debug.EnableBreakpoint

CTRL + F9

Toggles the breakpoint between disabled and enabled.

Make Datatip Transparent

[CTRL]

Causes a visible datatip to become transparent.

Notes:

- These key bindings are only available through the Visual C# Development Settings. To change to the Visual C# Development settings, go to Tools | Import and Export Settings and select Reset all Settings then select Visual C# Development Settings.

- To customize the key bindings for these commands, go to Tools | Options | Environment | Keyboard.

Tips and Tricks VS2005 and CS2008

source: http://blogs.msdn.com/karenliu/archive/2007/06/21/tips-and-tricks-for-vs20005-and-vs2008.aspx

Tips and Tricks for VS20005 and VS2008

Tips for Understanding Code

1) [VS 2008] Target Multiple Versions of the Framework

  • Use .NET 3.0 to target Vista
  • Use .NET 3.5 to get started with LINQ
  • Project | Properties | Application Tab

2) C# Development Settings

  • Share your settings
  • Tools | Import and Export Settings

3) Add New Item

  • [VS 2008] Categorical
  • Filter-as-you-type

4) Class Designer

  • Visual, high-level view of relationships in code
  • Use it to explore the framework

5) Active File Drop-down (Ctrl + Alt + Down Arrow)

  • Jump to active files

6) Collapse to Definition (Ctrl+M, 0)

  • Header-like view of code

7) Go to Definition (F12)

  • Quickly navigate to the definition

8) GTD Navigation Stack (Ctrl+Shift+7, Ctrl+Shift+8)

  • Virtual callstack

9) Find All References (Shift+F12)

  • Number of references
  • Cyclical

10) Iterate through List Window (F8)

  • Works on any list

11) Find Combo Box (Ctrl + /)

  • Go to line (Ctrl+G)
  • Go to file in project (Ctrl+Shift+G)
  • Help (keyword+F1)
  • Mini-command window (>)

Tips for Writing and Modifying Code

12) Rename

  • Entry points for rename (use solution explorer for file rename)
  • [VS 2008] Support for C# 3.0

13) Code Snippets

14) Invoke Smart Tag (Ctrl + .)

  • Never take your hand off the keyboard

15) Add Using

  • Automatically adds using directives

16) Generate Method Stub

  • Consume first, declare later

17) Snippets for Code Generation

18) [VS 2008] IntelliSense for Object Initalizers

  • Filter as you initialize
  • Ctrl+J for all members

19) [VS 2008] IntelliSense for Query Expressions

  • Full understanding

20) [VS 2008] Quick Info for C# 3.0 Understanding

  • Extension methods
  • Var

21) IntelliSense Customization

  • [VS 2008] CTRL for transparency
  • Tools | Options | Text Editor | C# | IntelliSense

22) [VS 2008] Customize Formatting Style

  • C# 3.0 Support
  • Tools | Options | Text Editor | C# | Formatting

23) Customize your Context Menu

  • Tools | Customize

24) [VS 2008] Debugging Query Expressions

  • IEnumerable Results View

25) [VS 2008] Organize Usings

  • Remove
  • Sort
  • Tools | Options | Text Editor | C# | Advanced

Loading Xps from MemoryStream

A common way of loading XpsDocument is to load it from file:

XpsDocument document = new XpsDocument(filename, FileAccess.Read, CompressionOption.NotCompressed);
FixedDocumentSequence fixedDocumentSequence = document.GetFixedDocumentSequence();
//To view in the DocViewer
docViewer.Document = fixedDocumentSequence as IDocumentPaginatorSource;


But if we need to Load the Xps from a Stream we can use the Package Class and do the following:

private void LoadXpsFromStream(Byte[] xpsByte, string packageUriString)
{
  MemoryStream xpsStream = new MemoryStream(xpsByte);
  using (Package package = Package.Open(xpsStream))
  //Remember to create URI for the package
  Uri packageUri = new Uri(packageUriString);
  //Need to add the Package to the PackageStore
  PackageStore.AddPackage(packageUri, package);
  //Create instance of XpsDocument
  XpsDocument document = new XpsDocument(package, CompressionOptions.MaximuCompression, packageUriString);
  //Do the operation on document here
  //Here I am viewing the document in the DocViewer
  FixedDocumentSequence fixedDocumentSequence = document.GetFixedDocumentSequence();
  //To view in the DocViewer
  docViewer.Document = fixedDocumentSequence as IDocumentPaginatorSource;
  //Remember to keep the Package object in PackageStore until all operations complete on document.
  //Remove the package from store
  PackageStore.RemovePackage(packageUri);
  doc.Close(); 
}

//Calling the above function from Client
//
//Get bytes[] from MemoryStream
//byte[] xpsBytes = someStream.ToArray();
//For demonstration I am reading bytes from a file
byte[] xpsBytes = File.ReadAllBytes(@”somexps.xps”);
//
LoadXpsFromStream( xpsBytes, “somexps.xps”);

Hope this helps.

Redirect to Login page on session expiration (ASP.NET)

Problem
Redirect the user to login page after a period of inactivity or when the session expires.

Investigation
A quick search on Google will find many articles which discuss how we can detect session expiration and how to redirect to the login page. However, most of the methods described require page refreshes or requests to the server to find out whether the session expired.

Some ways of detecting whether a session has expired:

1. ASP.NET Forum Article
If you are using cookie, you can store a marker in your cookie so you can tell the difference between “fresh browser + new session” and “old browser + expired session”. Below is sample code that will redirect the user to an expired page if the session has expired.

void Session_OnStart(Object sender, EventArgs e)
{
  HttpContext context = HttpContext.Current;
  HttpCookieCollection cookies = context.Request.Cookies;
  if (cookies[“starttime”] == null) {
    HttpCookie cookie = new HttpCookie(“starttime”, DateTime.Now.ToString());
    cookie.Path = “/”;
    context.Response.Cookies.Add(cookie); 
  }
  else {
    context.Response.Redirect(“expired.aspx”);
  }
}
souce: http://forums.asp.net/p/7504/7504.aspx

2. ASP Alliance Article

The ASP.NET HttpSessionState class provides a useful IsNewSession( ) method that returns true if a new session was created for this request.  The key to detecting a session timeout is to also look for the ASP.NET_SessionId cookie in the request.  If this is a new session but the cookie is present, this indicates a timeout situation. 

basePageSessionExpire.cs

 public class basePageSessionExpire : System.Web.UI.Page
 {
    public basePageSessionExpire()
    {
    }

  override protected void OnInit(EventArgs e)
  {
       base.OnInit(e);


   //It appears from testing that the Request and Response both share the 
   // same cookie collection.  If I set a cookie myself in the Reponse, it is 
   // also immediately visible to the Request collection.  This just means that 
   // since the ASP.Net_SessionID is set in the Session HTTPModule (which 
   // has already run), thatwe can't use our own code to see if the cookie was 
   // actually sent by the agent with the request using the collection. Check if 
   // the given page supports session or not (this tested as reliable indicator 
   // if EnableSessionState is true), should not care about a page that does 
   // not need session
   if (Context.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 (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))
     {
      Response.Redirect("sessionTimeout.htm");
     }  
    } 
   }
  }
}

sessionTimeout.htm

source: http://aspalliance.com/520_Detecting_ASPNET_Session_Timeouts.2


MSDN Forum Discussion


if(Session[“Session_name”]==null)

Response.Redirect(“Login.aspx”);

source: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1677554&SiteID=1

etc. etc a lot more out there….


Alternative Solution

Most of the methods suggested did not solve my problem as it required a request to be made to figure out whether the session has expired.

As the page served is stateless, it has no way to know whether the session in the server has expired until the page is refreshed/posted back.

The server session will time out after the period specified in the web.config, but it cannot auto-redirect the page on the client browser as the session has ended. Rather, the session can be programatically ended (using javascript) after a predetermined amount of time has elapsed.

What we can do is we can use an internal timer (javascript/ajax) that keeps track of the time since the last page request. In addition we need to know the Session Timeout value, and when the Session expiration time is reached we can programatically call Session.Abandon() and redirect to the Login page.

To implement this I had to create the following (ASP.NET 1.1):

BasePage.cs : This page has the capability to inject the javascript that will keep track of the time since the last page request, and when the session expiration time is reached, it redirects to logout.aspx. BasePage should be inherited by all pages that are required to be redirected.

public class BasePage : System.Web.UI.Page
{
  public SecurityApplicationPageBase()
  {
    this.Load += new System.EventHandler(this.Page_Load);
  }


  private void Page_Load(object sender, System.EventArgs e)
  {


    if(Session[“Session_name”]==null) 
    {
      Response.Redirect(“Login.aspx”);
    }
    InjectSessionExpireScript();    
  }


  // For  demo purpose the timeout is set to a smaller value. 
  //Remember The Javascript setTimeout works in milliseconds. 
  protected void InjectSessionExpireScript( )
  {
    string script = “<script> \n” +
    “function expireSession(){ \n”+
    ” window.location = ‘”+”Logout.aspx”+”‘}\n”+
    “setTimeout(‘expireSession()’, ” +this.Session.Timeout * 1000 +” ); \n”+
    “</script>”
    this.Page.RegisterClientScriptBlock(“expirescript”,script);
  } 
}

Logout Page: This page calls Session.Abandon() and redirects to the login.aspx page.

public class LogOut : BasePage
{
  private void Page_Load(object sender, System.EventArgs e)
  {
       Session.Abandon();
       Response.Redirect(“Login.aspx”,true); 
  }
}

Login Page: This page facilitates login. On a successful login a Session variable is created.

public class LogIn : System.Web.UI.Page
{

  private void btnLogin_Click(object sender, System.EventArgs e)
  {
    //when username and pasword is correct
    Session.Add(“Session_name”,”loggedinsuccessfully”);
  }
}

SomeOtherPage: Inherits BasePage. After a certain period of inactivity, this redirects to the logout page.

public class SomeOtherPage : BasePage
{
}

Rendered HTML
<HTML>
<HEAD>
</HEAD>
<BODY>
…….
<script>
function expireSession(){
window.location=’Logout.aspx’}
setTimeout(‘expireSession()’,20000);//20 sec
</script>
<div>some other page</div>


…..
</BODY>
</HTML>

Conclusion
As the page that is served is stateless, we cannot know whether the Session has really expired without sending a page request back to the server. What we did here is we used an internal timer (javascript) that keeps track of the time since the last page request. By knowing the the Session Timeout value we set a delay period and when the Session expiration time is reached we called Session.Abandon() and then the user is redirected to the Login page.