Search code examples
timerhttpmodule

Timer stops working in Http Module


I am trying to use a System.Threading.Timer to perform a task every five seconds in a Http Module and the timer just randomly stops firing:

using Bookbyte.IpFilter.Manager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;

namespace Bookbyte.IpFilter
{
    public class IpFilterModule : ApplicationStartModuleBase
    {
        private static object lockObject = new object();
        private static Timer timer;
        private static IpFilterManager filterManager;
        private static IEnumerable<string> blacklist;
        private static IEnumerable<string> whitelist;

        public override void OnInit(HttpApplication context)
        {
            context.BeginRequest += (object sender, EventArgs e) =>
            {
                var app = sender as HttpApplication;
                if (app != null)
                {
                    var ipAddress = app.Request.UserHostAddress;

                    if (!whitelist.Any(x => x == ipAddress))
                    {
                        if (blacklist.Any(x => x == ipAddress))
                        {
                            app.Context.Response.StatusCode = 404;
                            app.Context.Response.SuppressContent = true;
                            app.Context.Response.End();
                            return;
                        }
                    }
                }
            };

            base.OnInit(context);
        }

        public override void OnStart(HttpApplication context)
        {
            filterManager = new IpFilterManager();
            blacklist = new List<string>();
            whitelist = new List<string>();

            timer = new Timer(new TimerCallback((object sender) =>
            {
                lock (lockObject)
                {
                    blacklist = filterManager.GetBlacklist();
                    whitelist = filterManager.GetWhitelist();
                }
            }), null, 0, 5000);

            base.OnStart(context);
        }

        public override void Dispose()
        {
            timer.Dispose();
            base.Dispose();
        }
    }
}

And the ApplicationStartModuleBase:

using System.Web;

namespace Bookbyte.IpFilter
{
    public abstract class ApplicationStartModuleBase : IHttpModule
    {
        private static volatile bool applicationStarted = false;
        private static object applicationStartLock = new object();

        public void Init(HttpApplication context)
        {
            if (!applicationStarted)
            {
                lock (applicationStartLock)
                {
                    if (!applicationStarted)
                    {
                        this.OnStart(context);
                        applicationStarted = true;
                    }
                }
            }

            this.OnInit(context);
        }

        public virtual void OnInit(HttpApplication context)
        {
        }

        public virtual void OnStart(HttpApplication context)
        {
        }

        public virtual void Dispose()
        {
        }
    }
}

Solution

  • So I figured out the problem. The timer was being disposed in the module when the run time would call Dispose on the module.

    public override void Dispose()
    {
        timer.Dispose();
        base.Dispose();
    }
    

    Removing the call to timer.Dispose() fixed my issues.