Sunday, June 11, 2006

DotNetNuke, HttpContext & Scheduler

This post resolves an issue with the HttpContext in a scheduled task. I had created a function that deleted the users from a portal. The problem was that I could not invoke to UserController because the application crash throwing an “Object reference not set to an instance of an object” Exception.

The reason is the invocation to UserController needs to get the HttpContext and it does not exist during the execution of a scheduler task. The solution consists is create an HttpContext and use it. In order to do I get the code from this post and translate to C#.

public class SchedulerHttpContext

{

private static string appPhysicalDir;

public static void setHttpContextWithSimulatedRequest()

{

string appVirtualDir = "/";

if (appPhysicalDir == null)

{

if (Thread.GetDomain().GetData(".appPath") != null)

{

appPhysicalDir = Thread.GetDomain().GetData(".appPath").ToString();

}

else

{

throw new Exception("Error 1: CRASH!");

}

}

if (appPhysicalDir.Length == 0)

{

if (Thread.GetDomain().GetData(".appPath") != null)

{

appPhysicalDir = Thread.GetDomain().GetData(".appPath").ToString();

}

else

{

throw new Exception("Error 2: CRASH!");

}

}

Thread.GetDomain().SetData(".appPath", null);

string page = ((string)(System.Web.HttpRuntime.AppDomainAppVirtualPath + "/default.aspx")).TrimStart("/".ToCharArray());

string query = "";

StringWriter output = new StringWriter();

SimpleWorkerRequest workerRequest = new SimpleWorkerRequest(appVirtualDir, appPhysicalDir, page, query, output);

HttpContext.Current = new HttpContext(workerRequest);

}

}


 

When I need to retrieve the user information I only have to invoke to SchedulerHttpContext.setHttpContextWithSimulatedRequest() at the beginning. Here you can see an example of a SchedulerClient:


 

public class CleanUsers : DotNetNuke.Services.Scheduling.SchedulerClient

{

public CleanUsers(DotNetNuke.Services.Scheduling.ScheduleHistoryItem objScheduleHistoryItem)

: base()

{

this.ScheduleHistoryItem = objScheduleHistoryItem;

}

public override void DoWork()

{

this.Progressing();

this.ScheduleHistoryItem.AddLogNote("Begin Task!");

SchedulerHttpContext.setHttpContextWithSimulatedRequest();

soSomething(); //doSomething can call to UserController methods

this.ScheduleHistoryItem.AddLogNote("Finished Task");

this.ScheduleHistoryItem.Succeeded = true;

}

}

Saturday, June 10, 2006

Scheduled Task in DotNetNuke 4.0

DotNetNuke offers the possibility of schedule some tasks. In this document you will get the instructions to create a scheduled task. This is valid for .NET framework 1.1. The problem is that we need to specify where the assembly that contains the scheduled task is, and the compilation model in ASP.NET 2.0 compiles our classes dynamically and we cannot know what the assembly that contains the class is.

In this post of Shaun Walker we can get a solution. He proposes to publish our web site in order to get the assemblies of our portal. This solution is a good solution when you need to deploy the website, but when you are developing the scheduled tasks you have to publish all website to get the assembly. This is a waste of time and it is not necessary. We can generate the assembly from the command line in a few seconds. These are the steps:

  1. Create a SchedulerClient task. The class in the above document can be used as example.
  2. Save the file as “Scheduler.cs” for example.
  3. Compile the assembly from command line. If you are using VS 2005 you can do it from “Visual Studio 2005 Command Prompt” inside “Visual Studio Tools”. A valid command might be:
    csc /target:library /out:Scheduler.dll /r:.\ReferenceAssembly.dll,
    .\DotNetNuke.dll /recurse:Scheduler.cs

  4. Copy the generated assembly (Scheduler.dll) in the bin directory of the DotNetNuke portal.
  5. At this point you can follow the instructions in the document to configure the scheduled task.