So lesson learnt #1 - You can't programmatically create a timer job from a site collection feature. The reason for this is that typically the application pool that looks after the site does not have permission to write to the configuration database. Creating a Timer Job requires you to be able to write the timer job definition into the configuration database, so if your application pool doesn't have the rights, then the creation of the job will fail.
So basically you have to create a Web Application level feature (i.e. activated through Application Management tab of Central Admin) with a feature receiver method that creates the timer job. E.g.
<?xml version="1.0" encoding="utf-8"?>
<Feature Id="2DEA0BA9-A8D1-4475-AD0B-8FE25EBF65A2"
Title="Project Spaces Provisioning Timer Job"
Description="Add timer job required for project space provisioning."
Version="12.0.0.0"
Hidden="FALSE"
Scope="WebApplication"
DefaultResourceFile="core"
ReceiverAssembly="Collaboration.Projects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d76123a549458435"
ReceiverClass="Collaboration.Projects.FeatureCode.ProjectProvisioningTimerJob"
xmlns="http://schemas.microsoft.com/sharepoint/">
<elementmanifests>
</feature>
Creating the timer job in code is actually quite simple. Below is the feature activation/deactivation code:
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Collaboration.Projects.Provisioning;
namespace Collaboration.Projects.FeatureCode
{
///
/// Creates the timer job that runs the site creation process for confirmed requests in the provisioning request list
///
public class CollabProjectProvisioningTimerJob : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWebApplication application = properties.Feature.Parent as SPWebApplication;
DeleteProvisioningJob(application);
// install the job
ProjectSpaceCreationTimerJob provisioningJob = new ProjectSpaceCreationTimerJob(application);
SPMinuteSchedule schedule = new SPMinuteSchedule() { BeginSecond = 0, EndSecond = 59, Interval = 30 };
provisioningJob.Schedule = schedule;
provisioningJob.Update();
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
DeleteProvisioningJob(properties.Feature.Parent as SPWebApplication);
}
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}
///
/// Deletes the provisioning job if it exists
///
///
private void DeleteProvisioningJob(SPWebApplication application)
{
foreach (SPJobDefinition job in application.JobDefinitions)
{
if (job.Name == ProjectSpaceConstants.ProvisioningJobName)
job.Delete();
}
}
}
}
Now the ProjectSpaceCreationTimerJob class just inherits from SPJobDefinition. Below is a code snippet (note that the Execute method is the actually code that gets executed when the job runs).
using System;
using System.Net;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Collaboration.Projects.Resources;
using Collaboration.Provisioning;
using Collaboration.Common;
using System.Text;
namespace Collaboration.Projects.Provisioning
{
public class ProjectSpaceCreationTimerJob : SPJobDefinition
{
public ProjectSpaceCreationTimerJob() : base() { }
public ProjectSpaceCreationTimerJob(SPWebApplication web)
: base(ProjectSpaceConstants.ProvisioningJobName, web, null, SPJobLockType.Job)
{
this.Title = ProjectSpaceConstants.ProvisioningJobName;
}
public override void Execute(Guid targetInstanceId)
{
// your code goes here
base.Execute(targetInstanceId);
}
}
}
Hope this helps. I've written it down here so that I remember it in the future.
1 comment:
Hi Alan, nice post about TimeJobs on Sharepoint. Actually I have an application with two Windows Services to run and I was thinking about convert it into SP Timer Jobs so my customer could activate, deactivate and manage these services on an easy way. Do you think this scope could work well with SP Timer Jobs?
Thank you in advance.
Best Regards,
Edson Luiz Bassani
Post a Comment