SharePoint 2010 - Creating Custom Timer Job



A Timer Job is something that comes first in mind, when we start talking about batch processing / operations in SharePoint. Integration or synchronization of information across different applications is common scenario In most of the real-time SharePoint applications. In some cases information needs to synchronize every day or at a particular scheduled time and administration of scheduled/batch activities from a centralized place, All these could be achieved using a Custom Scheduled Job. Let's see how to build a Scheduled Job.

Create an empty SharePoint Project in Visual Studio 2010 and add a class for creating a scheduled Job.

DLL or Namespace reference required in the scheduled in the class

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;


Inheritance Required

The scheduled job class should be inherited from SPJobDefinition
Public class SampleJob : SPJobDefinition

Implementation Required

Class should implement three constructors shown Below.

Function Overrides

Custom Job Class should override the Execute method for implementing all logic required for Job execution. The Execute method will be called during the execution of the Job so we should write the code in this method or call another business class function from the execute method.

Custom Properties

We could add custom properties in the job so we could parameterize the Job execution. For example we need to pass some information into JOB so we could run the job based on the parameter. Custom properties come handy in this scenario. Declare a public member variable in the Job Definition class with a persistence attribute.

[Persisted()]
public string MyCustomProperty;

SPJobLockType:

ContentDatabase - this option locks the content database associated with the web application, but the job will be run for each content database associated with the web application.

Job - Ensures that the job will be run only on a single server.
None - Ensures that the Job will be run on all servers.

//Class should inherit from SPJobDefinition
Public class SampleJob : SPJobDefinition
{
       //You could Define Custom properties

        [Persisted()]
        public string MyCustomProperty;
 

///Implement following three constructors

          /// ****** Constructors *********

public SampleJob (): base(){

  }

public SampleJob (string jobName, SPService service, SPServer server,

                                    SPJobLockType targetType) : base (jobName,service

                                    , server, targetType) {

 }

public SampleJob (string jobName, SPWebApplication

webApplication): base (jobName, webApplication,

 null, SPJobLockType.Job) { 

}

/// ****** Constructors *********

//You should Override Execute Method
 

public override void Execute (Guid JobbId)

 {

//Your Job Execution code goes here

//In my case calls some external webservice and synchronizes the Data

          } 
  }

Here basically you will be inheriting from SPJobDefinition class and then implementing three of the constructors. Then comes the main function Execute method, where all of your real execution code goes. You have to watch for the lock type you specify in the constructor.

Adding Job in the web application

The Job definition needs to be added to the application so that only it will be recognized by SharePoint. One of the approaches is to implement the feature receiver class and over the FeatureActivated and FeatureDeActivating Events.

So add a new feature into the project and add feature receiver for the our feature.

public class SchedualedJobsFeature : SPFeatureReceiver
    {
       public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {

            using (SPSite site = new SPSite("http://localhost/Demosite"))
            {

              SPServer myServer = SPServer.Local;
              SPWebApplication myApplication = site.WebApplication;
                SPJobDefinitionCollection myJobsColl = myApplication.JobDefinitions;
                Type sPJobDefinitionType = typeof ( SPJobDefinition);

                Type[] types =  typeof  (SchedualedJobsFeature).Assembly.GetTypes ();

                foreach (Type t in types)
                {
                    if (t.IsSubclassOf(sPJobDefinitionType))
                    {
                        object[] atts= t.GetCustomAttributes (typeof(MyJobDefinitionAttribute)
                                    ,false );
                        if ( atts == null || atts.Length == 0)
                        {
                            continue;
                        }
                        MyJobDefinitionAttribute jobAttribute  = (MyJobDefinitionAttribute) atts[0];

                        SPJobDefinition job = (SPJobDefinition)Activator.CreateInstance(t,
                            jobAttribute  .Title, myApplication, myServer, jobAttribute .LockType );
                        job.Schedule = (SPSchedule) Activator.CreateInstance(jobAtt.ScheduleType);
                       
                        try
                        {
                            SPJobDefinition oldJob = myJobsColl[jobAttribute .Title ];
                            if (oldJob != null)
                            {
                                myJobsColl.Remove(oldJob.Id);
                            }
                            else
                            {

                            }
                        }
                        catch {}

                        try
                        {
                            job.Status = SPObjectStatus.Disabled;
                            myJobsColl.Add(job);
                        }
                        catch (Exception ex)
                        {
                            //Handle Exception
                        }

                    }
                }
            }

          }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            using (SPSite site = new SPSite("http://localhost/Demosite"))
            {
                SPServer myServer = SPServer.Local;
                SPWebApplication myApplication = site.WebApplication;
                SPJobDefinitionCollection myJobsColl = myApplication.JobDefinitions;

                Type sPJobDefinitionType = typeof(SPJobDefinition);
                Type[] types = typeof(SchedualedJobsFeature).Assembly.GetTypes();

                foreach (Type t in types)
                {
                    if (t.IsSubclassOf(sPJobDefinitionType))
                    {
                        object[] atts = t.GetCustomAttributes(typeof(MyJobDefinitionAttribute), false);
                        if (atts == null || atts.Length == 0)
                        {
                            continue;
                        }

                        MyJobDefinitionAttribute jobAtt = (MyJobDefinitionAttribute)atts[0];
                        try
                        {
                            SPJobDefinition job =(SchedualedJobsFeature) myApplication.JobDefinitions[jobAtt.Title];
                            myApplication.JobDefinitions.Remove(job.Id);
                        }
                        catch (Exception ex)
                        {
                            //Handle Exeception
                        }

                    }
                }
            }

         }

        }

Attrribute Class

public class MyJobDefinitionAttribute : Attribute
{
    public string Title
    {
        get;
        set;
    }
    public Type ScheduleType
    {
        get;
        set;
    }
    public SPJobLockType LockType
    {
        get;
        set;
    }
}


Programmatically Executing Scheduled Job

Some time you need to execute the timer job from a page button click or in specific event etc, then you have to find your Job definition and execute like following.

foreach (SPJobDefinition job in site.WebApplication.JobDefinitions) {
            if (job.Name == "My Job Name")
            job.Execute(new Guid());
        }

Debugging Timer Job

After creating timer job you should know how to debug it. For doing that one of the intresting things you should consider is which process needs to be attached to the Visual Studio project; any guesses? W3WP worker process? The answer is sharepoint timer service, so for timer jobs debugger should be attached to OWStimer.exe.
 

erver'>