Create Persistent ID Cookies

Also, build pageable DataGrids and run ASP.NET 1.0 and 1.1 side by side.





Create Persistent ID Cookies

Also, build pageable DataGrids and run ASP.NET 1.0 and 1.1 side by side.


By Jeff Prosise


Q: Can ASP.NET be configured to issue persistent session ID cookies? It issues temporary session ID cookies by default, meaning session state is lost when the browser is closed. I'd like to mimic the behavior of, which lets me close the browser and still see the contents of my shopping cart if I come back a week later.


A: ASP.NET lacks a simple configuration directive commanding it to issue persistent session ID cookies, but you can use a custom HTTP module to convert temporary session ID cookies into persistent ones (see Figure 1).


using System;

using System.Web;


public class PersistentSessionModule : IHttpModule


    public void Init (HttpApplication application)


        application.EndRequest +=

            new EventHandler (OnEndRequest);



    public void Dispose () {}


    void OnEndRequest (Object sender, EventArgs e)


        HttpCookie cookie =



        if (cookie != null)

            cookie.Expires = DateTime.Now.AddDays (7);



Figure 1. This HTTP module turns temporary ASP.NET session ID cookies into persistent ones.


An HTTP module is an object that sits in ASP.NET's HTTP pipeline and sees all incoming requests and outgoing responses. By registering to handle events fired from the pipeline, a custom HTTP module can hook into ASP.NET's request-processing plumbing and effect changes by modifying HTTP requests and responses as they pass through.


The module in Figure 1 registers a handler for EndRequest events - the very last event that fires before a fully formed HTTP response goes back to the client. The event handler checks each outgoing response for a cookie containing an ASP.NET session ID. If it finds that cookie in the response's Cookies collection, OnEndRequest converts the cookie into a persistent cookie by setting the cookie's Expires property to a date seven days hence. Now you can close the browser without losing your session state because the browser caches the cookie on the host machine's hard disk.


HTTP modules must be registered so they can be loaded by ASP.NET each time the host application starts up. The Web.config file in Figure 2 registers the HTTP module in Figure 1.





type="PersistentSessionModule, PersistentSessionModule" />




Figure 2. After you copy the compiled HTTP module into the application root's bin subdirectory, use this Web.config file to register it.


To deploy the module, first compile the source code in Figure 1 into a DLL named PersistentSessionModule.dll with the following command:


csc /t:library PersisentSessionModule.cs


Then move PersistentSessionModule.dll into the application root's bin subdirectory, and finish up by dropping Web.config into the application root.


If you extend the lifetime of ASP.NET session ID cookies to seven days, you'll need to extend session time-outs likewise. Otherwise, the cookie containing the session ID will hang around, but the session that it refers to will not. That's why the Web.config file in Figure 2 contains a element setting the session time-out to 10080 minutes, or seven days.


Also, be aware that increased session time-outs place greater demand on your session state store. If you store session state in a SQL Server database for a week at a time on a highly trafficked site, the database could grow quite large indeed!


Finally, note that Figure 1's OnEndRequest handler can optionally be placed in a Global.asax file rather than an HTTP module. Simply copy the code into Global.asax, rename the handler Application_EndRequest, and presto! You now have persistent session cookies.


Q: How much flexibility do I have in customizing the navigation bar that appears at the bottom of a pageable DataGrid? For example, how do I display the current page number between the left and right arrows? Can I also include double arrows that navigate to the first and last page?


A: You have infinite flexibility when modifying a DataGrid's page navigation bar (more commonly known as a pager). As long as what you want to display can be expressed in HTML, you can make it appear in a pager.


I've included a figure that shows a DataGrid with exactly the attributes you describe (see Figure 3). It even includes tooltips that appear when the user pauses the cursor over a pager arrow. The DataGrid is hosted in a page called CustomPager.aspx (for excerpts see Figures 4 and 5).


Figure 3. This DataGrid uses a custom pager that displays the current page number between left and right arrows as well as left and right double arrows.


Figure 4 shows how the DataGrid is declared in the ASPX file. Pay particular attention to the Font-Name, PrevPageText, and NextPageText attributes in the PagerStyle tag. Font-Name changes the pager's default font to Webdings. PrevPageText and NextPageText specify the Webdings character codes for the pager's arrows, producing the stylized left and right single arrows seen in Figure 3. This is a trick I learned from my good pal and fellow asp.netPRO columnist Dino Esposito, known to many simply as "Mr. DataGrid."


  Font-Name="Verdana" Font-Size="8pt" RunAt="server"

  Width="100%" AllowPaging="true" PageSize="16"

  Gridlines="vertical" OnPageIndexChanged="OnNewPage"





      ItemStyle-HorizontalAlign="center" />


      DataField="productname" />


      DataField="unitsinstock" />



    Font-Bold="true" HorizontalAlign="center" />



    Font-Name="Webdings" PrevPageText="3" NextPageText="4"

    HorizontalAlign="center" />

Figure 4. In this DataGrid declaration, the PagerStyle element creates left and right-pointing navigation arrows, while the OnItemCreated attribute provides a hook for further customizations (an excerpt from CustomPager.aspx).


Additional pager customizations are applied programmatically using the OnCustomizePager method in Figure 5, which fires in response to the DataGrid's ItemCreated events. OnCustomizePager's job is threefold: It adds double arrows, applies tooltips to all the arrows, and adds text showing the current page number. The method is accompanied by the OnGotoFirst and OnGotoLast methods, which navigate to the first and last page, respectively, when a user clicks on the double arrows. The double arrows are nothing more than LinkButton or Label controls; the LinkButtons are for active arrows and the Labels are for inactive ones. An arrow is "inactive" if it points left and the first page is currently displayed, or if it points right and the last page is currently displayed.


void OnCustomizePager (Object sender,

    DataGridItemEventArgs e)


    if (e.Item.ItemType == ListItemType.Pager) {

        DataGrid grid = (DataGrid) sender;

        TableCell pager = e.Item.Cells[0];


        // Add a double left arrow

        if (grid.CurrentPageIndex == 0) {

            Label label = new Label ();

            label.Font.Name = "Webdings";

            label.Font.Size = grid.PagerStyle.Font.Size;

            label.ForeColor = grid.PagerStyle.ForeColor;

            label.Text = "7";

            pager.Controls.AddAt (0, label);


        else {

            LinkButton button = new LinkButton ();

            button.Click += new EventHandler (OnGotoFirst);

            button.Font.Name = "Webdings";

            button.Font.Size = grid.PagerStyle.Font.Size;

            button.ForeColor = grid.PagerStyle.ForeColor;

            button.Text = "7";

            button.ToolTip = "Go to page 1";

            pager.Controls.AddAt (0, button);



        // Add a tooltip to the single left arrow

        if (grid.CurrentPageIndex != 0) {

            WebControl control =

                 (WebControl) pager.Controls[1];

            control.ToolTip = String.Format

                 ("Go to page {0}", grid.CurrentPageIndex);



        // Add a page number between arrows

        Label indicator = new Label ();

        indicator.Font.Name = "Verdana";

        indicator.Font.Size = grid.PagerStyle.Font.Size;

        indicator.ForeColor = grid.PagerStyle.ForeColor;

        indicator.Font.Bold = true;

        indicator.Text = String.Format ("Page {0}",

            grid.CurrentPageIndex + 1);

         pager.Controls.AddAt (2, indicator);





void OnGotoFirst (Object sender, EventArgs e)


    MyDataGrid.CurrentPageIndex = 0;

    BindDataGrid ();



void OnGotoLast (Object sender, EventArgs e)


    MyDataGrid.CurrentPageIndex =

        MyDataGrid.PageCount - 1;

    BindDataGrid ();


Figure 5. OnCustomizePager fires in response to ItemCreated events and customizes the DataGrid's pager (an excerpt from CustomPager.aspx).


This sample is merely the tip of the iceberg when it comes to pager customizations. Remember, your only constraints are those inherent to HTML. Other than that, the possibilities are endless.


Q: Can ASP.NET 1.0 and 1.1 run side by side? More to the point, is it possible to run some ASP.NET apps under version 1.1 and others under version 1.0 on the same Web server? And can an application programmatically determine the version of ASP.NET that hosts it?


A: Yes, yes, and yes. That was easy, wasn't it? Seriously, though, ASP.NET 1.0 and 1.1 coexist very well on the same server. You'll find helpful information at Here, however, is a synopsis.


By default, installing version 1.1 of the .NET Framework configures existing ASP.NET applications to use ASP.NET 1.1. You can revert a specific application to ASP.NET 1.0 by changing the version of Aspnet_isapi.dll that the application is mapped to in the IIS metabase from 1.1.4322 to 1.0.3705. The easy way to do that is to run the Aspnet_regiis utility that comes with version 1.0 of the .NET Framework. This Aspnet_regiis command configures the application in the MyApp virtual directory to use ASP.NET 1.0:


Aspnet_regiis -sn w3svc/1/root/myapp


If you decide later to migrate the application to ASP.NET 1.1, simply repeat the command, but use the Aspnet_regiis utility that comes with version 1.1 this time.


As for detecting the ASP.NET version at run time, the code in Figure 6 contains the source for a page that does just that.






Figure 6. This page displays the version of ASP.NET that hosts it.


It uses the Framework's static Environment.Version property to grab the major and minor version numbers. Should you need them, build and revision numbers are also present in the System.Version object the property's get accessor returns.


The sample code in this article is available for download.


Jeff Prosise is the author of several books, including Programming Microsoft .NET (Microsoft Press, 2002). He's also a cofounder of Wintellect (, a software consulting and education firm that specializes in .NET. Have a question for this column? Submit queries to [email protected].




Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.