Introduction
Let's say for example that you have to calculate the value of some fields in your database every hour from 8am to 8pm, but you don't have full control of the server where your web application is running; this is a common scenario and my project will provide you the tools to make the job possible.
Schedule Tasks for web applications is not always easy. If we have full control of the host server it's not a problem, but sometimes we don't so we cannot do something like, easily create a console application that performs the tasks that we need for our web application, and then add the compiled EXE to the Schedule Task list of the server.
Let me remind you that web applications don't work the same as Windows applications; if we want to keep our web application alive we have to make periodic requests to it.
Background
Here is another Web Based Scheduler � it uses a different approach to solve the same problem. The sample code in this article has all you need to implement and manage your own Tasks and add them to the Scheduler Service.
One of the most important differences with the other article is that this code uses a Web Service so you can integrate with any application, also force the implementation of the Tasks to follow some pattern, because it uses a base class.
Using the Code
The sample code contains 6 projects:
CsharpTask
, this project contains a sample task writed in C#
SchedulerService.Core
, this project contains the Task base class, inherited from this class to implement your own Task
SchedulerService.Entities
, this project contains a Dataset that represents the Scheduled Tasks also contain some constants
SchedulerService.KeepAlive
, this project is a console application that makes a call to the Web service, run this app periodically to ensure that the Scheduler will be running
SchedulerService.UI
, this project contains a couple of windows forms, used to manage the Scheduled Tasks running on the web service
WS.Scheduler
, this is the core of the project, here is implemented all the functionallity needed to run the scheduled tasks
If you just want to use the Service as it is and want to implement your own task:
- Setup the
WS.Scheduler
Web Service on your Web Server
- Create a new Class Library Project in Visual Studio (no matter the language)
- Add a reference to the
SchedulerService.Core
project
- Create you class and make it inherit from the base class
Task
- Implement the three required methods
Execute, LogEntry
and CancelTask
(more about this later)
- Compile your project and add the DLL file to the bin folder of the Web Service
- Configure the SchedulerService.UI.exe.config file if needed, this is the app.config of the SchedulerService.UI project. You may have to configure the URL where your Scheduler service is running, the default location is: http://localhost/Scheduler/Scheduler.asmx
- Run the UI project and add your task
- Now that your task is ready to run, make periodic calls to your Web Service to keep it alive, you can use the included console application, you have to setup the URL of the web service in the app.config also.
How to Create a New Task
To create a task that can be scheduled in the service you have to create a Class Library Project in the language of your preference, then add a reference to the SchedulerService.Core project, and create your class and make it inherit from the Task
base class. Your implementation for the class before you add any custom code must look like this:
C#
using System;
using System.Collections.Generic;
using System.Text;
namespace CsharpTask
{
class MyTask : SchedulerService .Core .Task
{
public override void Execute()
{
throw new Exception("The method or operation is not implemented.");
}
public override void CancelTask(string Message)
{
throw new Exception("The method or operation is not implemented.");
}
public override void LogEntry(string Entry)
{
throw new Exception("The method or operation is not implemented.");
}
}
}
VB.NET
Public Class MyTask
Inherits SchedulerService.Core.Task
Public Overrides Sub CancelTask(Optional ByVal Message As String = "")
End Sub
Public Overrides Sub Execute()
End Sub
Public Overrides Sub LogEntry(ByVal Entry As String)
End Sub
End Class
The only code that you really have to implement is the Execute
method for your class. The implementation of LogEntry
and CancelTask
methods are optional � write the code if you really need it.
It is a good practice to use Try/Catch blocks in your code. The Task
class has a property named AbortAfter
� this property is used to abort a task if the task has not finished after X minutes. If you are planning to use this feature you will need to implement a Try/Catch block because when the task is aborted it raises a System.Threading.ThreadAbortException
. Also, you have to run the RaiseTaskFinishedEvent
method after the task has been finished, otherwise the scheduler will not work properly. If you catch an exception in the code, you can use the RaiseTaskExceptionEvent
to stop and disable the task while you find the cause of the exception. Here is a complete template for an Execute
method:
C#
public override void Execute()
{
try
{
base.RaiseTaskFinishedEvent(this.TaskID, DateTime.Now);
}
catch (System.Threading.ThreadAbortException ex)
{
}
catch (System.Exception ex)
{
base.RaiseTaskExceptionEvent(this.TaskID, DateTime.Now,ex);
}
}
VB.NET
Public Overrides Sub Execute()
Try
MyBase.RaiseTaskFinishedEvent(Me.TaskID, DateTime.Now)
Catch ex As System.Threading.ThreadAbortException
Catch ex As Exception
MyBase.RaiseTaskExceptionEvent(Me.TaskID, DateTime.Now, ex)
End Try
End Sub
The sample code contains two test classes, VB.NET (in the same project as the Web Service) and C# (in a separated project), both do the same thing: they write some entry to a log file. Also, they have code so you can test the AbortAfter
feature. If the task has defined a value it will enter in some infinite loop (of course, just for test purposes).
That's all you need to know to implement your own Task.
How the Scheduler Service Works
I am not going to put detailed information here of how the Scheduler service works, I just will give an overview of some of the code files in the WS.Scheduler project.
The Scheduler Service has the following methods that you can use to manage the service:
GetTaskList, this method returns a list of all scheduled tasks in the
Service.
AddTask, this method is used to add a new task to the Scheduler Service.
DeleteTask, used to delete a task.
UpdateTaskList, use this method to update the scheduled tasks.
RunTasksNow, used to run a task now.
CancelTask, this method stops the execution of a task.
GetAvailableTasks, return a list of all available classes that inherit
from the 'Task' base class. this method will look in
all assemblies in the /bin folder of the Web Service.
KeepAlive, you can call this method to keep the Web Service running.
The Scheduler Service has code inside Global.asax
to initialize and handle the Scheduler.
The service uses the Application_Start
method to initialize a Threading.Timer
object, you can modify the web.config(key="period")
to change the default period of time between timer callbacks, but right now the default period is 120000 miliseconds. The minimum value that you can setup is 30000 miliseconds.
The Timer callback (Timer_Handler
method) is where the Scheduler checks if there are any task that must be executed. This method also checks if any of the tasks that are running have expired their allowed time of execution as defined by the AbortAfter
property of the task.
The SchedulerController.vb
is the core of the Scheduler. This class contains the implementations of the methods exposed by the Web Service, also has the code to manage the execution and cancellation of the Scheduled Tasks.
I just want to comment on the following methods:
GetAvailableTasks
, this method will check all DLL's and EXE's in the bin folder of the Web Services and will look for classes that inherit from the Task
base class. To do this I am using the Assembly class and the BaseType property of the class Type. If you want to change how the Task will behave after it has been finished (if you called the RaiseTaskFinishedEvent
method) change the TaskFinished
method of the SchedulerController
, if you want to change what happens when an exception is thrown (if you are using Try/Catch blocks and you are using the RaiseTaskExceptionEvent
method) change the code of the TaskException
method in the scheduler controller.
The method SincronizeTaskObjectAndDataRow
is in charge of synchronizing the Dataset and the SchedulerController list of Task objects.
Points of Interest
Right now the List of Scheduled Tasks is being stored as an XML file because I wanted to provide a tool that did not require any DB. However, I prefer to store the task list in some Database.
Remember, there is a lot of room for improvement in how to schedule a task, so check and compare the options that you have in the Windows Scheduled Tasks application to see what I mean. In this sample, there is no authetication or security checks, so I highly recomended that you implement some sort of security check. The other thing that you have to implement is the code for cancelling a running task from the UI.
History
VB.NET Code V1.0