Home > Sample chapters

Understanding AJAX and ASP.NET

The Timer

In addition to causing partial-page updates through an event generated by a control (such as a button click), AJAX includes a timer to cause regularly scheduled events. You can find the Timer control alongside the other standard AJAX controls in the Toolbox. By dropping a Timer on a page, you can generate automatic postbacks to the server.

Some uses for the Timer include a "shout box”—like an open chat where a number of users type in messages and they appear near the top like a conversation. Another reason you might like an automatic postback is if you wanted to update a live Web camera picture or to refresh some other frequently updated content.

The Timer is very easy to use—simply drop it on a page that hosts a ScriptManager. The default settings for the timer cause the timer to generate postbacks every minute (every 60,000 milliseconds). The Timer is enabled by default and begins firing events as soon as the page loads.

Here’s an exercise using the Timer to write a simple chat page that displays messages from a number of users who are logged in. The conversation is immediately updated for the user typing in a message. However, users who have not refreshed since the last message don’t get to see it—unless they perform a refresh. The page uses a Timer to update the conversation automatically. At first, the entire page is refreshed. Then, the chat page uses an UpdatePanel to update only the chat log (which is the element that changes).

Using the Timer to create a chat page

  1. Open the AJAXORama application if it’s not already open. The first step is to create a list of chat messages that can be seen from a number of different sessions. Add a global application class to the project by right-clicking in Solution Explorer and clicking Add New Item. Choose Global Application Class as the type of file to add. This adds files named Global.asax and Global.asax.cs to your Web site.

  2. Update the Application_Start method in Global.asax.cs to create a list for storing messages and add the list to the application cache.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.SessionState;
    
    namespace AJAXORama
    {
      public class Global : System.Web.HttpApplication
    {
      protected void Application_Start(object sender, EventArgs e)
      {
        // Code that runs on application startup
        List<string> messages = new List<string>();
        HttpContext.Current.Cache["Messages"] = messages;
      }
      // other generated code is here...
    }
    
    
    }
  3. Create a chat page by adding a new page to the Web site and calling it GroupChat.aspx. This will hold a text box with messages as they accumulate, and it also gives users a means of adding messages.

  4. When the messages are coming in, it would be very useful to know who sent which messages. This page forces users to identify themselves first; then, they can start adding messages. First, type in the text Group Chatting… after the ScriptManager. Give it a large font style with block display so that it’s on its own line. After that, type in the text First, give us your name:. Then, drag a TextBox control from the Toolbox onto the page. Give the TextBox the ID TextBoxUserID. Drop a Button on the page so that the user can submit his or her name. Give it the text Submit ID and the ID ButtonSubmitID.

  5. Drop another TextBox onto the page. This one will hold the messages, so make it large (800 pixels wide by 150 pixels high should do the trick). Set the TextBox’s TextMode property to MultiLine, and set the ReadOnly property to True. Give the TextBox the ID TextBoxConversation.

  6. Drop one more TextBox onto the page. This one will hold the user’s current message. Give the TextBox the ID TextBoxMessage.

  7. Add one more Button to the page. This one enables the user to submit the current message and should include the text Add Your Message. Be sure to give the button the ID value ButtonAddYourMessage. The following graphic shows a possible layout of these controls:

    httpatomoreillycomsourcemspimages605033.png
  8. Open the code-beside file GroupChat.aspx.cs for editing. Add a method that retrieves the user’s name from session state:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    
    public partial class GroupChat : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }
    
        protected string GetUserID()
        {
            string strUserID =
              (string) Session["UserID"];
            return strUserID;
        }
    }
  9. Add a method to update the UI so that users may type messages only after they’ve identified themselves. If the user has not been identified (that is, the session variable is not there), disable the chat conversation UI elements and enable the user identification UI elements. If the user has been identified, enable the chat conversation UI elements and disable the user identification UI elements:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    
    public partial class GroupChat : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }
        // other code goes here...
        void ManageUI()
        {
            if (GetUserID() == null)
    
            {
                 // if this is the first request, then get the user's ID
                 TextBoxMessage.Enabled = false;
                 TextBoxConversation.Enabled = false;
                 ButtonAddYourMessage.Enabled = false;
    
                 ButtonSubmitID.Enabled = true;
                 TextBoxUserID.Enabled = true;
            }
            else
            {
                 // if this is the first request, then get the user's ID
                 TextBoxMessage.Enabled = true;
                 TextBoxConversation.Enabled = true;
                 ButtonAddYourMessage.Enabled = true;
    
                 ButtonSubmitID.Enabled = false;
                 TextBoxUserID.Enabled = false;
            }
        }
    }
  10. Add a Click event handler for the Button that stores the user ID (ButtonSubmitID). The method should store the user’s identity in session state and then call ManageUI to enable and disable the correct controls:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public partial class GroupChat : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }
       // other page code goes here...
        protected void ButtonSubmitID_Click(object sender, EventArgs e)
        {
            Session["UserID"] = TextBoxUserID.Text;
            ManageUI();
        }
    }
  11. Add a method to the page for refreshing the conversation. The code should look up the message list in the application cache and build a string that shows the messages in reverse order (so the most recent is on top). Then, the method should set the conversation TextBoxConversation’s Text property to the new string (that is, the text property of the TextBox showing the conversation):

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public partial class GroupChat : System.Web.UI.Page
    {
       // other page code goes here...
        void RefreshConversation()
        {
            List<string> messages = (List<string>)Cache["Messages"];
            if (messages != null)
            {
                string strConversation = "";
    
                int nMessages = messages.Count;
    
                for(int i = nMessages-1; i >=0; i--)
                {
                    string s;
    
                    s = messages[i];
                    strConversation += s;
                    strConversation += "\r\n";
                }
    
                TextBoxConversation.Text =
                    strConversation;
            }
        }
    }
  12. Add a Click event handler for adding your message by double-clicking the Button for adding your message (the lower button on the form) and adding a Click event handler to respond to the user submitting his or her message (ButtonAddYourMessage). The method should grab the text from the user’s message TextBoxMessage, prepend the user’s ID to it, and add it to the list of messages held in the application cache. Then, the method should call RefreshConversation to make sure the new message appears in the conversation TextBox:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public partial class GroupChat : System.Web.UI.Page
    {
        // Other code goes here...
        protected void ButtonAddYourMessage_Click(object sender,
                                                   EventArgs e)
        {
            // Add the message to the conversation...
            if (this.TextBoxMessage.Text.Length > 0)
            {
                List<string> messages = (List<string>)Cache["Messages"];
                if (messages != null)
                {
                    TextBoxConversation.Text = "";
    
                    string strUserID = GetUserID();
    
                    if (strUserID != null)
                    {
                        messages.Add(strUserID +
                            ": " +
                            TextBoxMessage.Text);
                        RefreshConversation();
                        TextBoxMessage.Text = "";
                    }
                }
             }
         }
    }
  13. Update the Page_Load method to call ManageUI and RefreshConversation:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    using System.Xml.Linq;
    using System.Collections.Generic;
    
    public partial class GroupChat : System.Web.UI.Page
    {
        // Other code goes here...
        protected void Page_Load(object sender, EventArgs e)
        {
            ManageUI();
            RefreshConversation();
        }
    }
  14. Now run the page to see how it works. After you’ve identified yourself, you can start typing in messages—and you’ll see them appear in the conversation TextBox. Try browsing the page using two separate browsers. Do you see an issue? The user typing a message gets to see the message appear in the conversation right away. However, other users involved in the chat don’t see any new messages until after they submit messages of their own. You can solve this issue by dropping an AJAX Timer onto the page.

  15. Drag a ScriptManager from the AJAX controls onto the page. Then, drag a Timer from the AJAX controls onto the page. Although the AJAX Timer starts generating postbacks automatically, the default interval is 60,000 milliseconds, or once per minute. Set the Timer’s Interval property to something more reasonable, such as 10,000 milliseconds (or 10 seconds).

    Now run both pages and see what happens. You should see the pages posting back automatically every 10 seconds. However, there’s still one more issue with this scenario. If you watch carefully enough, you’ll see that the whole page is refreshed—even though the user name is not changing. During the conversation, you’re really only interested in seeing the conversation TextBox updated. You can fix this by putting in an UpdatePanel.

  16. Drag an UpdatePanel from the AJAX controls onto the page. Position the UpdatePanel so that it can hold the conversation text box. Move the conversation text box so that it’s positioned in the UpdatePanel. Modify the UpdatePanel’s triggers so that it includes the Timer’s Tick event. Now run the chat pages, and you should see only the conversation text box being updated on each timer tick. The following graphic shows the new layout of the page employing the UpdatePanel:

The ASP.NET AJAX Timer is useful whenever you need regular, periodic posts back to the server. You can see here how it is especially useful when combined with the UpdatePanel to do periodic partial-page updates.