Here are a few tips about scheduled tasks that may spare you some debugging and angry moments.
First of all, if you are interested in how you create a simple scheduled job, please check out Ted Nybergs post.
Several developers / Load balancing environment
If the same site is up’n’running on several computers/servers but with a shared database, the scheduled job might run at the “wrong” machine. There is a setting in web.config which controls if the scheduler should be run by this instance or not. It’s an attribute to <siteSettings> called “enableScheduler”, eg. <siteSettings enableScheduler=”false” …. /> if you don’t want the scheduler to run in this instance/machine.
Another way, not to tell if the job should be executed or not, but if you want to know which computer that executed the job, is to return the computer name with the return message. This can save you a lot of frustration when are about to pull you hair of cause the changes you make in to code doesn’t affect to job. 🙂
return "[Computer: " + System.Environment.MachineName + "] " + returnMessage;
Object reference not set to an instance…
Sometimes when you work with scheduled jobs, you can get this error, even though the only thing your job does is to return a “hellow world”. I’ve experienced this a few times, but never put much effort in to find out what causes this.
However, you can easily go around this by deleteing your job and create a new one with a slightly different class name.
Impersonate
In some cases you might need to run to job as a certain user.
Specially when you want to use FindPagesWithCriteria in EPiServer CMS 5 R2. It ignores the AccessControlList and only fetches pages that the current user has access rights to read. In R2 SP1 there is a new method called FindAllPagesWithCriteria which is supposed to find all pages despite access rights.
Well, this is how you login:
[ScheduledPlugIn(Description = "Test job with impersonated user", DisplayName = "Test job")]
public class TestJob
{
public static string Execute()
{
string returnMessage;
if (EnterImpersonatedState("erik.nordin", "password"))
{
returnMessage = "Job executed with user " + PrincipalInfo.CurrentPrincipal.Identity.Name;
LeaveImpersonatedState();
}
else
{
returnMessage = "Failed to login";
}
return "[Computer: " + System.Environment.MachineName + "] " + returnMessage;
}
private static IPrincipal prevPrincipal;
private static bool EnterImpersonatedState(string userName, string password)
{
IPrincipal impersonatedUser = null;
// If you don't want to validate the user, you can use skip the if-statement:
if (Membership.ValidateUser(userName, password))
{
impersonatedUser = PrincipalInfo.CreatePrincipal(userName);
}
if (impersonatedUser == null)
{
return false;
}
prevPrincipal = PrincipalInfo.CurrentPrincipal;
PrincipalInfo.CurrentPrincipal = impersonatedUser;
return true;
}
private static void LeaveImpersonatedState()
{
PrincipalInfo.CurrentPrincipal = prevPrincipal;
}
}