If you are searching for instructions on how to write your own DotNetNuke scheduled task, then you've come to the right blog post. This article discusses the steps that I take in order to write a task that I need DotNetNuke to perform periodically for me.
DotNetNuke has several little-known gems that can add some powerful functionality to your web site. Scheduled tasks are one of those gems that a lot of people don't know about, or at least don't take advantage of. As we've seen in the past, the documentation on the DotNetNuke web site is either out of date, incorrect, or incomplete. So to remedy this, and hopefully get more people writing their own scheduled task, I'm going to show you how I go creating a custom scheduled task. I'll also share some working examples that will help you get started quickly.
On with the show.
Start Using DLLs
As far as I am aware, scheduled tasks need to be compiled into a DLL file. This seem to be implied in the document, though I haven't seen anywhere that explicitly states this. If you are already building DNN modules using the Web Application Project (WAP) method, then all you need to do is create your scheduled task inside your normal project. WAPs will compile nicely up into one or more DLL files without any fuss.
If you haven't taken the jump to using WAP, and you're using WST (Web Site Project), or you don't write custom DNN modules at all, then you have the option of creating your scheduled task inside its own Class Library project. You will need Visual Studio 2005 or 2008 to do this. Class Library projects compile up into a DLL file quite nicely. If you are using VB, make sure that you sent the root Namespace of your project to blank. This is KEY! You will also need to add a reference to the DotNetNuke.dll to your Class Library project. DotNetNuke.dll can be found in the bin directory of your DotNetNuke installation.
If you don't have access to Visual Studio 2005 or 2008, and are using Visual Web Developer Express to write DNN modules, then you might be out of luck. Visual Web Developer Express doesn't compile into DLLs for distribution. However, you might want to look into using Visual Studio Express... it might be able to compile to DLL. Perhaps one of the other readers can suggest a method.
Sub-Class From SchedulerClient
Once you have nailed down a method for rolling your code into a DLL file, you can begin writing your scheduled task. All of your scheduled tasks begin by sub-classing from the DotNetNuke.Services.Scheduling.SchedulerClient class.
Example - C#:
class ScheduledTaskExample : SchedulerClient
Example - VB:
Public Class ScheduledTaskExample
Inherits SchedulerClient
Overload Your Class Constructor
The next thing that DotNetNuke requires from a scheduled task is an overloaded constructor that accepts a DotNetNuke.Services.Scheduling.ScheduleHistoryItem object. This overloaded constructor must also call the constructor of its parent class. This is done by using the base() syntax in C#, and the MyBase.New() syntax in VB. The final thing that your constructor must do is assign the ScheduleHistoryItem parameter to the ScheduleHistoryItem property of the class. Here is an example of a constructor that meets these requirements:
Example - C#:
public ScheduledTaskExample(ScheduleHistoryItem objScheduleHistoryItem)
: base()
{
ScheduleHistoryItem = objScheduleHistoryItem;
}
Example - VB:
Public Sub New(ByVal objScheduleHistoryItem As ScheduleHistoryItem)
MyBase.New()
Me.ScheduleHistoryItem = objScheduleHistoryItem
End Sub
Override DoWork() Method
The DoWork() method is the entry point for the execution of your scheduled task. When the DotNetNuke portal determines that it is time for your scheduled task to run, it creates an instance of your class and calls its DoWork() method. So this is where you put all your custom functionality.
There are a few things to keep in mind when writing this method. First, you need to include logic that alerts the portal to whether or not your task succeeded at whatever it needed to do. The way you do this is by enclosing your code within a try-catch block. If your code runs as planned, then you set the Succeeded property of the ScheduledHistoryItem member to true. Otherwise, you set the Succeeded property to False. In the catch portion of your try-catch block you will also want to set the Succeeded property to False so that when an exception is thrown, the scheduled task will report that it failed.
Example - C#:
public override void DoWork()
{
try
{
// do some stuff ...
// then report success to the scheduler framework
ScheduleHistoryItem.Succeeded = true;
}
// handle any exceptions
catch (Exception exc)
{
// report a failure
ScheduleHistoryItem.Succeeded = false;
// log the exception into
// the scheduler framework
ScheduleHistoryItem.AddLogNote("EXCEPTION: " + exc.ToString());
// call the Errored method
Errored(ref exc);
// log the exception into the DNN core
Exceptions.LogException(exc);
}
}
Example - VB:
Public Overrides Sub DoWork()
Try
' do some stuff ...
' then report success to the scheduler framework
ScheduleHistoryItem.Succeeded = True
Catch ex As Exception
' handle any exceptions
' report a failure
ScheduleHistoryItem.Succeeded = False
' log the exception into
' the scheduler framework
ScheduleHistoryItem.AddLogNote("EXCEPTION" + ex.ToString())
' call the Errored method
Errored(ex)
' log the exception into the DNN core
Exceptions.LogException(ex)
End Try
End Sub
You will notice in the examples above that there are a few other things you should do when an exception occurs. You should log the exception into the scheduler framework which allows you to view the exception in your scheduler's history page. This is done by calling the AddLogNote() method on the ScheduleHistoryItem member. Secondly, you need to call the parent class's Errored() method so it can take its own necessary actions. Lastly, you should log the exception into the DNN core exception log by calling the LogException method on the DotNetNuke.Services.Exceptions.Exceptions class.
Compile & Install
Once you are finished overriding the DoWork() method you are ready to compile and install your new scheduled task. Compiling instructions will vary depending upon what tool and project type you are using, so I will not discuss those details here. Once you are compiled up into a DLL file you will want to copy the DLL file into the bin directory of your DNN Web site installation.
To install your new task you go into Host menu > Schedule page and click on the Add Item to Schedule link.
Then enter the full class name, followed by a comma, followed by the name of your DLL. Like so:

Configure it up, hit Update, and you should be good to go.
Some Tips
Since scheduled tasks do not run in the context of a Web page execution, nor in the context of any particular DotNetNuke portal, you will often need to find alternative ways to access the information that your task requires. Instead of Server.Globals.MapPath() use System.Web.HttpRuntime.AppDomainAppPath to get the file path to your DNN installation. If your task uses some of the DNN framework methods that require you to pass the ID of a portal, then you can either use a PortalController to get all of the portal IDs and loop through them, or you can access particular portal IDs by storing and retrieving them using System.Configuration.ConfigurationSettings.AppSettings. AppSettings allows you to store configuration information inside the .config files within the .Net configuration hierarchy. Likewise for tab IDs and module IDs, you may have to manually store and retrieve these from in a .config file.
Another thing to keep in mind is that the Add/GetSetting methods on the ScheduleHistoryItem class really suck. You might be tempted to use it, but you'll quickly be scratching your head because there are no easy ways to update an existing setting. So you will need to find an alternate method to store settings for your scheduled task.
Working Examples!!!
Here is an example of a working scheduled task. It writes out a file to the root folder of your web application.
C# Version - ScheduledTaskExample.cs:
using System;
using System.IO;
using System.Web;
using DotNetNuke.Services.Scheduling;
using DotNetNuke.Services.Exceptions;
namespace Kemmis.Examples.DotNetNuke
{
class ScheduledTaskExample : SchedulerClient
{
public ScheduledTaskExample(ScheduleHistoryItem objScheduleHistoryItem)
: base()
{
ScheduleHistoryItem = objScheduleHistoryItem;
}
public override void DoWork()
{
try
{
// perform some task
String strPath = HttpRuntime.AppDomainAppPath + "CS_DID_IT.TXT";
using (StreamWriter sw = new StreamWriter(strPath, true))
{
sw.WriteLine(DateTime.Now.ToString() + " - C# DID IT!");
sw.Close();
}
// report success to the scheduler framework
ScheduleHistoryItem.Succeeded = true;
}
catch (Exception exc)
{
ScheduleHistoryItem.Succeeded = false;
ScheduleHistoryItem.AddLogNote("EXCEPTION: " + exc.ToString());
Errored(ref exc);
Exceptions.LogException(exc);
}
}
}
}
VB Version - ScheduledTaskExample.vb:
Imports DotNetNuke.Services.Scheduling
Imports DotNetNuke.Services.Exceptions
Imports System
Imports System.Web
Imports System.IO
Namespace Kemmis.Examples.DotNetNuke
Public Class ScheduledTaskExample
Inherits SchedulerClient
' requires a special constructor which
' accepts a ScheduleHistoryItem
Public Sub New(ByVal objScheduleHistoryItem As ScheduleHistoryItem)
MyBase.New()
Me.ScheduleHistoryItem = objScheduleHistoryItem
End Sub
Public Overrides Sub DoWork()
Try
' perform some tasks
Dim strPath As String = HttpRuntime.AppDomainAppPath + "VB_DID_IT.TXT"
Using sw As StreamWriter = New StreamWriter(strPath, True)
sw.WriteLine(DateTime.Now.ToString() + " - VB DID IT!")
sw.Close()
End Using
' report success to the scheduler framework
ScheduleHistoryItem.Succeeded = True
Catch ex As Exception
ScheduleHistoryItem.Succeeded = False
ScheduleHistoryItem.AddLogNote("EXCEPTION" + ex.ToString())
Errored(ex)
Exceptions.LogException(ex)
End Try
End Sub
End Class
End Namespace