Home
    Shop
    Advertise
    Write For Us
    Affiliate
    Newsletter
    Contact

Using Task Scheduler or Windows Service For Scheduled Tasks

There are scenarios when ASP.NET web application needs to execute some code on regular basis. That could be creating of some reports every day, sending a reminder e-mail, keep website alive by calling dummy page every 10 minutes, backup data etc. ASP.NET has not straightforward and reliable solution for tasks like these. Using pure ASP.NET, you can simulate scheduled tasks and this could work well in simple cases. This could be only option if you are on shared hosting. To learn how to simulate scheduled tasks using ASP.NET only, see Scheduled Tasks in ASP.NET tutorial.

Problem with ASP.NET only methods is that ASP.NET application could restart or even stop work because of numerous reasons. When this happens, scheduled task could delay execution or not execute at all.

Because of this, for time critical tasks that must be executed in specified time, developers usually choose more reliable, external solution like using of custom Windows service or Windows Task scheduler.

Scheduled tasks using Windows service

If you have dedicated hosting, you can install Windows service on server that will execute scheduled tasks. On shared hosting, users usually can't install Windows services, but you can run Windows service on another computer that will call web page or web service on web server. Under Windows section, Visual Studio contains template for Windows Service project, which automatically creates basic structure for new Windows service. Service code includes class constructor, OnStart and OnStop methods:

[ C# ]

using System.ServiceProcess;
   
namespace TestWindowsService
{
  public partial class Service1 : ServiceBase
  {
   public Service1()
   {
    InitializeComponent();
   }
   
   protected override void OnStart(string[] args)
   {
   }
   
   protected override void OnStop()
   {
   }
  }
}

[ VB.NET ]

Public Class Service1
   Protected Overrides Sub OnStart(ByVal args() As String)
   ' Add code here to start your service. This method should set things
   ' in motion so your service can do its work.
   End Sub
   
   Protected Overrides Sub OnStop()
   ' Add code here to perform any tear-down necessary to stop your service.
   End Sub
   
End Class

Windows services are more reliable for scheduled tasks than pure ASP.NET because ASP.NET application could stop or restart in many cases. If ASP.NET application doesn't work because process is recycled by server, any scheduled task also doesn't execute.

There are many different reasons that cause ASP.NET application to restart. That could be changing of web.config file, change in /bin folder, change of Global.asax file, change in App_Global_Resources or App_Local_Resources folders, change in App_Code folder etc. Also, if in some period there is no visitors on your site (e.g. in night hours), web server will force ASP.NET application to shutdown and your scheduled tasks will not run until someon visits website.

Implementation code is almost the same for both win services and ASP.NET methods. In Scheduled Tasks in ASP.NET tutorial, there are two examples that use Timer.Elapsed and Thread.Sleep to create a task loop. These ideas are useful for Windows service approach too. Instead of using Application_Start in Global.asax, in Windows service we'll use OnStart method to initially create loop with Timer or Thread, and start scheduled task.

Here is an example of Windows service that uses new thread to make periodic calls class method (scheduled task):

[ C# ]

using System.ServiceProcess;
   using System;
   using System.Threading;
   
   namespace TestWindowsService
   {
   public partial class Service1 : ServiceBase
   {
   public Service1()
   {
   InitializeComponent();
   }
   
   protected override void OnStart(string[] args)
   {
   // When Windows service starts, creates and starts separate thread
   ThreadStart tsTask = new ThreadStart(TaskLoop);
   Thread MyTask = new Thread(tsTask);
   MyTask.Start();
   
   }
   
   static void TaskLoop()
   {
   // In this example, task will repeat in infinite loop with while(true)
   // You can add additional parameter here if you want to have an option
   // to stop and restart the task from some external control panel
   while (true)
   {
   // First, execute scheduled task
   ScheduledTask();
   
   // Then, wait for certain time interval, in this case 1 hour
   System.Threading.Thread.Sleep(TimeSpan.FromHours(1));
   }
}
   
   static void ScheduledTask()
   {
   // Task code which is executed periodically
   
   }
   
   protected override void OnStop()
   {
   // Here you can add a logic to inform you  if Windows service
   // is stopped, so you will know that your tasks are not executing
   }
   }
   }

[ VB.NET ]

Imports System
   Imports System.Threading
   
   Public Class Service1
   
   Protected Overrides Sub OnStart(ByVal args() As String)
   ' When windows service starts, creates an starts separate thread
   Dim tsTask As ThreadStart = New ThreadStart(AddressOf TaskLoop)
   Dim MyTask As Thread = New Thread(tsTask)
   MyTask.Start()
   End Sub
   
   Shared Sub TaskLoop()
   ' In this example, task will repeat in infinite loop using while(true)
   ' You can additional parameter if you want to have an option
   ' to stop the task from some page
   While (True)
   
   ' First, execute scheduled task
   ScheduledTask()
   
   ' Then, wait for certain time interval, in this case 1 hour
   System.Threading.Thread.Sleep(TimeSpan.FromHours(1))
   End While
   End Sub
   
   Shared Sub ScheduledTask()
   ' Task code which is executed periodically
   
   End Sub
   
   Protected Overrides Sub OnStop()
   ' Add code here to perform any tear-down necessary to stop your service.
   End Sub
   
   End Class

OnStop method executes when service is stopped. OnStop is very useful to send a message and inform you know that scheduled tasks are not executing because of some reason, you can also write error information into log etc.

Scheduled tasks with Windows service, which uses System.Timers.Timer class could look like this:

[ C# ]

using System.ServiceProcess;
   
namespace TestWindowsService
{
 public partial class Service1 : ServiceBase
 {
  public Service1()
  {
   InitializeComponent();
  }
   
  protected override void OnStart(string[] args)
  {
   // Dynamically create new timer
   System.Timers.Timer timScheduledTask = new System.Timers.Timer();
   
   // Timer interval is set in miliseconds,
   // In this case, we'll run a task every minute
   timScheduledTask.Interval = 60 * 1000;
   
   timScheduledTask.Enabled = true;
   
   // Add handler for Elapsed event
   timScheduledTask.Elapsed +=
   new System.Timers.ElapsedEventHandler(timScheduledTask_Elapsed);
  }
   
  void timScheduledTask_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
  {
   // Execute some task
   FirstTask();
  }
   
  void FirstTask()
  {
   // Here is the code we need to execute periodically
   
  }
   
  protected override void OnStop()
  {
   // Here you can add a logic to inform you  if Windows service
   // is stopped, so you will know that your tasks are not executing
  }
 }
}

[ VB.NET ]

Imports System
 Public Class Service1
   
  Protected Overrides Sub OnStart(ByVal args() As String)
   ' Dynamically create new timer
   Dim timScheduledTask As System.Timers.Timer = New System.Timers.Timer()
   
   ' Timer interval is set in miliseconds,
   ' In this case, we'll run a task every minute
   timScheduledTask.Interval = 60 * 1000
   
   timScheduledTask.Enabled = True
   
   ' Add handler for Elapsed event
   AddHandler timScheduledTask.Elapsed, AddressOf timScheduledTask_Elapsed
  End Sub
   
  Sub timScheduledTask_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
   ' Execute some task
   FirstTask()
  End Sub
   
  Sub FirstTask()
   ' Here is the code we need to execute periodically
   
  End Sub
  Protected Overrides Sub OnStop()
   ' Add code here to perform any tear-down necessary to stop your service.
  End Sub
   
End Class

Use System.Threading.Thread or System.Timers.Timer class for scheduled tasks?

Theoretically both examples above do the same job. In practice, Timer class has better performances. Using of Thread.Sleep is often considered as bad design and waste of resources. Another possible problem occurs if you need to stop Windows service. Solution with Timer will stop quickly, but thread that sleeps is not accessible. During the sleep time, service is frozen and you can't stop it.

Also, Timer class is created to measure time. It works more accurately than Thread.Sleep which could wait longer than you specify. This is important if you work with short time intervals.

For most cases, both methods will probably work fine and both are easy to implement. But, because of small advantages above, I would recommend using of Timer class.

Scheduled tasks using Windows Task Scheduler and .Net console application

Solution that uses Windows Task Scheduler is similar to using Windows service. You will also need full access to web server, so this option often not available on shared hosting. Windows Task Scheduler is built as a solution for scheduled tasks with many options and features. It is easy to use with intuitive user interface. You can find it in Start menu, under All Programs -> Accessories -> System Tools -> Task Scheduler.

In case that you need quick solution, it is easier to use Windows Task Scheduler than build Windows Service from scratch. But if you creating web application that will have installation wizard, you can automate things with Windows service and make scheduled task as a part of your installation. Windows Task Scheduler has options to start a program or script, send an email or display a message. If task should call ASP.NET page, then you have to do it indirectly. In this case, some developers suggest creating a task that opens Internet Explorer and add page URL as parameter, where command line could look like this:

iexplore http://www.yourdomain.com/ScheduledTask.aspx

This works fine, Task Scheduler will open an Internet Explorer and load .aspx page, but someone needs to close the browser after page is loaded. And problem is even bigger if task should be repeated in short time intervals. The possible solution could be to kill IE process, but that not sounds like right way for me. I think it is better to write small console application in C# or VB.NET that uses System.Net.WebClient class to make web request and close when task is finished. This application will have one parameter: an URL to visit.

So, to make this application, start a new Console Application Project and name it WebTask. The code of the application is very simple:

[ C# ]

using System;
using System.Text;
using System.Net;
   
namespace WebTask
{
 class Program
 {
  static void Main(string[] args)
  {
  // Create web client
  WebClient wc = new WebClient();
   
  string WebURL = args[0];
  UTF8Encoding encUTF8 = new UTF8Encoding();
  string ReturnedData = "";
   
  try
  {
   // Call a page or web service and read returned data
   ReturnedData = encUTF8.GetString(wc.DownloadData(WebURL));
   
   // In addition to this, we can do something with returned data,
   // like check if task was successful, make some analysis etc.
   
  }
  catch (Exception ex)
  {
   // Something goes wrong, you can
   // write information about exception in log, databse,
   // send an email etc.
   
   }
  }
 }
}

[ VB.NET ]

Imports System.Net
   Imports System.Text
   
   Module Module1
   
   Sub Main()
   ' Create web client
   Dim wc As WebClient = New WebClient()
   
   Dim WebURL As String = Environment.CommandLine
   Dim encUTF8 As UTF8Encoding = New UTF8Encoding()
   Dim ReturnedData As String = ""
   
   Try
   ' Call a page or web service and read returned data
   ReturnedData = encUTF8.GetString(wc.DownloadData(WebURL))
   
   ' In addition to this, we can do something with returned data,
   ' like check if task was successful, make some analysis etc.
   
   Catch ex As Exception
   ' Something goes wrong, you can
   ' write information about exception in log, databse,
   ' send an email etc.
   
   End Try
   End Sub
   
   End Module

Now you can use this application in Task Scheduler and call it instead of messy Internet Explorer. Not only that application could run in background and close itself after task is finished. Also, you have complete control over other possible issues. You can analyze XML data returned from web service or web page, check returned HTTP status code to know when web server is down etc.

Should I use Task Scheduler or Windows service?

Windows Task Scheduler and Windows service solutions have some similarities. They both demand full access to server, so you probably can't use them on shared hosting. They are preferred solutions for large websites with a lot of traffic that run on dedicated servers. If I compare them from the business side, I would said that using Task Scheduler requires less working time, since you don't need to create new Windows service. Task Scheduler is mature application that has a lot of features. In fact, Task Scheduler is also running as Windows service in background, you can find it in Local Services list. It could be used by administrator, and tasks can be added or changed any time. Your job as a developer is just to create tasks applications when needed. This sounds easy to test and maintain.

When using custom Windows service you need to write code for tasks, but also create new service from scratch, implement and test same logic that you have in Task Scheduler. Since Task Scheduler is also Windows service (you can find it in Local Services list), and if you provide some GUI for your windows service you practically end up with Task Scheduler that already exists on your computer. This sounds like waste of time in most cases, so personally I would say that Task Scheduler should be your first choice because implementation is quick and simple. When Task Scheduler can't satisfy project requirements, consider custom Windows service is an option.

You should know that Task Scheduler also has its drawbacks. Shortest time interval in Task Scheduler is 1 minute. If your task should run every 10 seconds, then Windows service remains as the option.

Also, when new task is created in Task Scheduler, you have to specify which Windows account will be used to run task. Task Scheduler stores account's password and all is working fine. Until account password is changed! If account password is changed (and some security templates requires changing of passwords after x days), you must update it manually in Task Scheduler for every task. Otherwise your tasks will not execute and even worse, you will not get any information about it. Password updating could be very tedious if you have a lot of tasks.

Solution for this is to change suggested account to NT AUTHORITY/SYSTEM or NT AUTHORITX/NETWORK SERVICE.

Scheduled tasks in ASP.NET using DotNetPanel, Plesk or Helm

Most web servers have some kind of web hosting automation program, like DotNetPanel, Plesk, Helm etc. Applications like these have many features that make maintenance of website easier. They also include support for scheduled tasks. Notice that either your Helm or DotNetPanel support scheduled task feature, it could be disabled by your hosting provider (sometimes they do this to save server's resources). But, if this option is enabled on your web server, it can be quick and also reliable solution.

If your web hosting provider disabled scheduled task in web control panel, there is an option to try some third party service. Some websites, like weetasks.com offers scheduled tasks service for free. Personally, I didn't try it yet, but if claims on website are true, it looks acceptable. If you tolerate that your scheduled tasks depends of someone else.

Conclusion

As you see, there are really a lot of ways how you can implement scheduled tasks in ASP.NET web application. Scheduled Tasks in ASP.NET tutorial covers pure ASP.NET solutions. Here, I mentioned external options, like Windows services, Windows Task scheduler, hosting automation programs or even external websites. As most secure option, I found using of Windows service. But, that doesn't mean that I will use Windows service for every case.

Creating and especially maintaining of Windows service can take significant time. Very often, problem can be solved quickly by adding new scheduled task in Helm Control Panel. What is important to you is to know which options exist. Then, choose what is best for your specific case.

Happy coding!


Tutorial toolbar:  Tell A Friend  |  Add to favorites  |  Feedback  |   Google