Tuesday, June 16, 2015

Timer job in SharePoint for specific site



  • Creating custom Timer job
  • How to execute Timer job for a specific site (without changes to web config and without any static siteurl)
  • How to pass values to property bag of Timer job from feature
The following code creates Timerjob class that inherits from SPJobDefinition

using System;
using System.Collections.Generic;
using System.Web;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;

namespace TestSharepointProject
{
    public class TimerJob : SPJobDefinition
    {
        SPWeb mySiteWeb;
        string mySiteUrl = "";
        public TimerJob(SPWebApplication webApp): base("TimerJob", webApp, null, SPJobLockType.ContentDatabase)
        {
            this.Title = "TimerJob";
        }
        public TimerJob():base()
        {
        }
        public override void Execute(Guid targetInstanceId)
        {
            if (!string.IsNullOrEmpty(this.Properties["mySiteUrl"].ToString()))
            {
                mySiteUrl = this.Properties["mySiteUrl"].ToString();
            }

            if (!string.IsNullOrEmpty(mySiteUrl))
            {
                using (SPSite mySite = new SPSite(mySiteUrl))
                {
                    using (mySiteWeb = mySite.OpenWeb())
                    {
                        //provide your logic here for the site
                    }
                }
            }

        }
    }
}
In the above code,the timer job is getting property “mySiteUrl” and creating the site object. The default constructor is required as in the above code, otherwise error will come.
Now our timer job class is ready and we will see how we can add key value pairs in the property bag of our custom timer job class.
Create a feauture “TimerJobFeatureReceiver” with scope as web. Following is the code for the feauture reciever which adds key values.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace TestSharepointProject
{
    public class TimerJobFeatureReceiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            try
            {

                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    SPWeb web = properties.Feature.Parent as SPWeb;
                    web.AllowUnsafeUpdates = true;
                    SPWebApplication webApp = web.Site.WebApplication;
                    foreach (SPJobDefinition job in webApp.JobDefinitions)
                        if (job.Name == "TimerJob") job.Delete();

                    string key = "mySiteUrl";
                    string value = web.Url;

                    TimerJob tmrJob = new TimerJob(webApp);
                    //remove the key if already exists
                    bool isKeyExists = tmrJob.Properties.ContainsKey(key);
                    if (isKeyExists)
                    {
                        tmrJob.Properties.Remove(key);
                    }
                    tmrJob.Properties.Add(key, value);
                    SPMinuteSchedule schedule = new SPMinuteSchedule();
                    schedule.BeginSecond = 0; //to start immediately
                    // schedule.EndSecond = 59; //use this if timer job is to end after some seconde
                    schedule.Interval = 60; //number of minutes
                    tmrJob.Schedule = schedule;
                    tmrJob.Update();

                    web.AllowUnsafeUpdates = false;
                });
            }
            catch (Exception ex)
            {
                //log exception if any
            }
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            try
            {
                //remove the scheduled job
                SPSecurity.RunWithElevatedPrivileges(delegate()
                 {
                     SPWeb web = properties.Feature.Parent as SPWeb;
                     web.AllowUnsafeUpdates = true;
                     SPWebApplication webApp = web.Site.WebApplication;
                     foreach (SPJobDefinition job in webApp.JobDefinitions)
                         if (job.Name == "TimerJob") job.Delete();
                     web.AllowUnsafeUpdates = false;
                 });
            }
            catch (Exception ex)
            {
                //log exception if any
            }
        }
    }
}
One generic way I generally prefer is; create a custom list. Provide key value columns in the list.
Read the custom list in feature acitvation event and add those values in the timerjob property bag. In this way we can maintain config values to
timer job without any changes to web.config just to read some key values.

Remarks

Make sure that the user with whom we are activating the feature should have valid permission as the code is dealing with timer job.
We may encounters some errors like
Access denied.
at Microsoft.SharePoint.Administration.SPPersistedObject.Update()
at Microsoft.SharePoint.Administration.SPJobDefinition.Update()
at Pages.SurveyFeatureReceiver.<>c__DisplayClass1.b__0()

Its suggestable to activate the feature from command prompt and we won’t be getting the above though both are running with same user.
Following is the quick code to activate or deactivate the feature by stsadm
Activating the feature
stsadm -o activatefeature -fileName TimerJobFeatureReceiver\Feature.xml -url http://adicodes/sites/mysite -force
Deactivating the feature
stsadm -o deactivatefeature -fileName TimerJobFeatureReceiver\Feature.xml -url http://adicodes/sites/mysite -force

No comments:

Post a Comment