First time at my blog? Check out the table of contents! x
posted on Saturday, March 08, 2008 12:00 PM | Filed Under [ DotNetNuke Asp.Net Open Source ]

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.

 

image

 

Then enter the full class name, followed by a comma, followed by the name of your DLL. Like so:

 

image

 

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

 

Comments Leave Yours...
Tony
5/13/2008 11:27 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Thanks for the informative aricle, I appreciate the good explanations as well as code examples to digest. One additional piece of information that I have yet to find is how to programmatically add a schedule task without having to go to the UI. I see the core Events module is doing this for the reminders, do you know how to do this? I assume there is either an API call, a sproc to use, or a table to insert into, but I am just not finding the information.

Rafe
5/16/2008 7:06 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Hi Tony, I finally got around to looking into this. Here's a good starting point:

DotNetNuke.Services.Scheduling.SchedulingProvider.Instance.AddSchedule(objScheduleItem)

Where objScheduleItem is a populated instance of DotNetNuke.Services.Scheduling.ScheduleItem

Hope this helps! I might just go ahead and add another post to the blog with an example of this.

Thanks for reading!

Rafe
5/21/2008 7:43 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

For information on how to programmatically modify scheduled tasks, see this post:

http://kemmis.info/blog/archive/2008/05/20/programmatically-add-delete-and-update-scheduled-tasks.aspx

Baldwin's DNN
6/15/2008 9:34 AM
# 推荐系列:Scheduler,Reset skin等(2008年第2期)

[1] DNN Scheduler Mechanism,翻译过来即为调度任务机制。<br />调度管理是DNN提供给开发者在一定的时间间隔实现调度任务的一种机制。利用你可以定制开发满足需求的调度任务,它也是在DNN典型模式(提供者模式)的基础上实现的,故可不更改核心代码就创建新的或修改原有的调度服务。关于如何使用DNN调度任务机制请查看我曾经在博客园的相关文章:<br />DNN调度管理解析(一)-----简单介 ...

Marty
7/16/2008 10:04 PM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Hi Rafe,

Thanks for the post - right in line with what I'm building. However, since I'm relatively new to all this, it would help if you could fill in a few more blanks for myself and others like me.

In my case, I've built a module, and built and tested the code that needs to execute on a scheduled task, but now I need to get the schedule code into a dll. That's where I'm missing something.

I'm using the DotNetNuke starter kit under VS2005 as a web site. I took from your notes that I could add a Class Library project under my DotNetNuke solution, drop my class in there and all would be good, but I'm lost on how to resolve the references to code in my Module for accessing the DataProvider functions and such.

Any help would be greatly appreciated!

Marty

Rafe
7/17/2008 6:08 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Marty,

In your case you will want to change the output path setting in your class library setting so that the resulting dll file is placed into the bin directory of your dotnetnuke installation.

When a class library is compiled you end up with a dll file, like DotNetNukeScheduledTaskExample.dll, placed by default in the bin\Debug or bin\Release subdirectories of your class library project folder. Your DotNetNuke installation has no knowledge or access to those folders. So, you have to either manually move the dll into the bin directory of the DotNetNuke project, or set the output path in the class library project to be the bin directory of the DotNetNuke project, so that the dll file is placed their every time you build. You can find this settings in the "Build" section of the class library properties window.

Brian
5/6/2009 11:25 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Your tip about blanking out the root namespace for vb code was a lifesaver. Thanks!!

Priya
6/2/2009 4:45 PM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

I want to use some keys from GlobalResouceFile in Schedular.
I tired using the following DotNetNuke.Services.Localization.Localization.GetString("MessageSent.Text", DotNetNuke.Services.Localization.Localization.GlobalResourceFile);
I tired all possible methods like
GetSystemMessage() etc.

but didn't help.
Can you point me in the right direction?

Kent
7/19/2009 8:42 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Hi,

Big THANKS for mentioning the step of blanking the Root Namespace. I've been trying to get scheduled code running and I could not figure out why it wouldn't. Great stuff!

Cheers,
Kent

NweLay
8/2/2009 4:12 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

I would like to know where we can write code in dotnetnuke.

Mike Durthaler
8/10/2009 8:51 PM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

This was really informative. I read one other post before this one which really explains things well but this includes the full "Theory and Operation." I learned a lot and lucked out that the examples are founded on what I need to use for mine.

I'm going to write a class that examines times stamps on files and if they've changed, uploads them. It will automate what we want to do where I'm developing.

This is 90% of the solution.

software developers
8/20/2009 1:19 PM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Quite inspiring,

I loved your tips specially Your tip about blanking out the root namespace

Thanks for writing, most people don't bother.

andrew
2/7/2010 5:45 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

One additional piece of information that I have yet to find is how to programmatically add a schedule task without having to go to the UI. I see the core Events module is doing this for the reminders, do you know how to do this?

I'd like to know this too!

Alessandro
2/15/2010 4:09 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Hi,
i've a great problem.
I've write class in vb to install a schedule task in DNN.
Namespace: "ProvaScheduler.Mail",
Class name: "SchedulerMail."
Assembly: SchedulerMail_1

I've compiled DLL into bin directory of DotNetNuke and add a schedule in the portal with this informations:
Full Class Name and Assembly: ProvaScheduler.Mail.SchedulerMail, SchedulerMail_1
Schedule Enable: Yes
Time Laps: 10 Minute
Retry Frequency: 5 Minute

But the scheduler DON'T START !!!

CAN YOU HELP ME ?
THANKS.


This is my code:
Imports Microsoft.VisualBasic
Imports DotNetNuke
Imports DotNetNuke.Services.Scheduling
Imports DotNetNuke.Services.Exceptions
Imports System.IO
Imports System.Web

Namespace ProvaScheduler.Mail
Public Class SchedulerMail
Inherits SchedulerClient

Public Sub New(ByVal objScheduleHistoryItem As ScheduleHistoryItem)
MyBase.New()
Me.ScheduleHistoryItem = objScheduleHistoryItem
End Sub

Public Overrides Sub DoWork()
Try
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
Me.ScheduleHistoryItem.AddLogNote("Prova OK")
Me.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


Laurence
2/23/2010 12:35 PM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Hi,
I have a custom module containing code for a custom scheduled task (from yourr guide - thanks!). The scheduled task works fine when run by the scheduler, but now I have a new requirement:

I want to kick start the scheduled task from my module code. In case you are wondering why - the scheduled task calls a rather long running process which I want to execute in a separate thread to the thread the module code runs in.

I haven't found a way through the API to do this ..... does anyone have a tip?

Many thanks.

Amritesh kumar singh
3/8/2010 11:46 PM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

Thanks for the informative article, I appreciate the good explanations as well as code examples to digest

kevin j.
5/5/2010 11:06 AM
# re: How to Write a Custom DotNetNuke SchedulerClient (i.e. a Scheduled Task)

rafe,

your blog post tutorial saved me hours of messing around with DNN scheduled tasks!

the only issue i had was improperly entering the full class path in the Full Class Name and Assembly textbox. i entered the namespace comma DLL file name and forgot append the class name to the namespace. if you don't enter this correctly, the task won't run but the problem isn't obvious.

thanks and keep it gangsta,

kj

Post Your Comment

Title
Required
Name
Required
Email
Optional
Url
Optional
Comment  
Please add 8 and 3 and type the answer here:

Who Is Rafe

rafe

Rafe Kemmis

I am an audacious web developer with a double bachelor of science in Computer Science and Mathematics. I specialize in Microsoft ASP.Net, Silverlight, and Adobe ActionScript.

Questions?

Always a thoughtful response. You may post your question on an article, or contact me directly.

Hire Me.

I provide custom solutions to complex problems. I can help your business no matter how large or small.

Contact me now.

Subscribe