Dot Net Perls

System.Timers Tutorial - C#

by Sam Allen

Problem

Your ASP.NET website or other program is critical and you must keep it running. You want to use a System.Timer to periodically check to make sure it is working correctly. Run diagnostics in the Timer event and ensure your site is functioning.

Solution: C# and System.Timers

Your company's website must be kept running uninterrupted, but you are tired of late-night calls. Fortunately, we have the System.Timers namespace that allows us to run checks programmatically.

Information: looking at the Timer class

MSDN states that System.Timers "allows you to specify a recurring interval at which the Elapsed event is raised in your application. You can then handle this event to provide regular processing."

In other words, using Timer for periodic checks is a really common requirement and it can work very well. In fact, Microsoft recommends it. [Timer Class - (System.Timers) - msdn.microsoft.com]

Next, MSDN notes that "you could create a service that uses a Timer to periodically check the server and ensure that the system is up and running." And that is exactly the problem I needed to solve.

Task: adding Timer to a C# class

Your ASP.NET application should have an App_Code folder, and you can put a C# .cs file in it that will store a static timer object. For reference, I have materials on global variables in ASP.NET, which apply to this subject. [ASP.NET - Global Variables Example - dotnetperls.com]

The code that follows is a static class, meaning it cannot have instance members or fields. It includes the System.Timers namespace and shows the Elapsed event function.

Just for the example, the code appends the current DateTime to a List every three seconds. Further down in the document, we see the code that reads the List.

using System;
using System.Collections.Generic;
using System.Timers;

public static class TimerExample          // In App_Code folder
{
    static Timer _timer;                  // From System.Timers
    static List<DateTime> _l;             // Stores timer results
    public static List<DateTime> DateList // Gets the results
    {
        get
        {
            if (_l == null)               // Lazily initialize the timer
            {
                Start();                  // Start the timer
            }
            return _l;                    // Return the list of dates
        }
    }
    static void Start()
    {
        _l = new List<DateTime>();        // Allocate the list
        _timer = new Timer(3000);         // Set up the timer for 3 seconds
        //
        // Type "_timer.Elapsed += " and press tab twice.
        //
        _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
        _timer.Enabled = true;            // Enable it
    }
    static void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        _l.Add(DateTime.Now);             // Add date on each timer event
    }
}
  1. The Timer is initialized lazily.
    The Start method above is called when the property DateList is accessed. This part isn't required but can provide a cleaner approach.
  2. The result List is allocated.
    The List here is just for the example. Your Timer will have more complex behaviors.
  3. The Timer is initialized.
    The Timer constructor receives an interval figure in milliseconds. The event is hooked up to Elapsed, and Enabled is set to true.

What the code above does is populate the List with the current time every three seconds. First, here are some important parts of the Timer class in System.Timers.

Information: important parts of the Timer class

As shown above, you need to add the System.Timers namespace at the top of your file for easy access to Timer. Here are some properties, methods and events from Timer.

Timer memberWhat it is used for
Timer.AutoResetMSDN: this indicates "whether the Timer should raise the Elapsed event each time the specified interval elapses or only after the first time it elapses." That means if you want a recurring timer, leave this as true.
Timer.Enabled"Whether the Timer should raise the Elapsed event." You must set this to true if you want your timer to do anything.
Timer.IntervalThis indicates "the time, in milliseconds, between raisings of the Elapsed event. The default is 100 milliseconds." You will almost certainly want to make this interval longer than the default. For example, for 30 seconds, use 30000 as the Interval.
Dispose
Disposed
Timers allocate system resources, so if you are creating a lot of them, make sure to Dispose them. This gets complicated fast. I suggest just using a single static timer.
Timer.StartThis does the same thing as setting Enabled to true. I am not certain why we need this duplicate method.
Timer.StopThis does the same thing as setting Enabled to false. [See Timer.Start]
Timer.Elapsed EventThis is the event that is invoked each time the Interval of the Timer has passed. You must specify this function in your code. To add the event, you can press tab twice after typing "_timer.Elapsed +=". [See first code example above]

Task: using the Timer code in your ASPX file

Your .aspx file should have a code-behind file, and this next example shows how you can use the first code in this article. If your project uses web forms, you should assign the List values to asp:Literal, asp:Label, or other objects.

using System;
using System.Web;
using System.Web.UI;

public partial class _Default : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        HttpResponse r = Response;                    // Get reference to Response
        foreach (DateTime d in TimerExample.DateList) // Get the timer results
        {
            r.Write(d);                               // Write the DateTime
            r.Write("<br/>");                         // Write a line break tag
        }
    }
}

It starts the Timer from the DateList property accessor, and then writes all the contents of the List to the page output. This shows us that the timer code is working.

With this Default.aspx page, you can use the Reload button in your web browser, and you will see the timer is adding to the List every 3 seconds.

Note that this is not an AJAX timer, and for live page updates, you will need a different client-side mechanism. AJAX timers would not work for critical server-side checks.

Information: common ASP.NET Timer gotcha

Often developers can hit an "Object reference not set to an instance of an object" error when using HttpContext.Current in the Timer. This is because the Timer is invoked on a separate thread.

I do not fully understand why this is, but you can work around the problem by storing important variables in static, global fields or properties.

Question: how do you use Timer in your website?

I use Timer to check the filesystem for changes to my App_Data folder, and when new files are detected, they are parsed and checked for errors. This way, my website should almost always use the most recent valid file.

Again, for mission-critical sites, you should have logic that tries to detect all errors and then handle them. This can mean visitors to your site don't encounter the errors and you detect them on the Timer.

Summary: using Timer in your project

This interval-based validation approach is recommended by Microsoft for mission-critical applications. If you are maintaining or developing an important site, using Timers to try to handle all errors and report them is an excellent technique.

Just imagine that you are on a vacation on a tropical island, and you are assured your company's site is working properly, and thousands of people are filling their shopping carts and placing orders without any errors.

System.Timers and Timer in C# can't assure you of 100% reliability, but they can move your development in that direction. When you are on that tropical island, you can thank Dot Net Perls.

Dot Net Perls
About
Sitemap
Language Features
Struct Examples and Tricks
Run Commands With Process.Start
Enum Tips and Examples
ThreadPool and Progress UI
DllImport, dllexport Interop
New
StartsWith String Examples
GZIP Accept-Encoding Request
© 2008 Sam Allen. All rights reserved.