Creating Timer Jobs in SharePoint 2010 That Target Specific Web Applications (Wrox)

Summary: Learn how to create a SharePoint 2010 timer job that is associated with a SharePoint 2010 web application.

Wrox logo

Wrox SharePoint Books

Applies to: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Author: Bryan Phillips

Editors: WROX Tech Editors for SharePoint 2010 Articles

Contents

  • Overview of Timer Jobs in SharePoint 2010

  • Preparing to Create a SharePoint Timer Job

  • Creating a SharePoint Timer Job

  • Enabling Configuration for Your SharePoint Timer Job

  • Deploying Your Timer Job

  • Testing and Debugging Your SharePoint Timer Job

  • Conclusion

  • About the Author

  • Additional Resources

Overview of Timer Jobs in SharePoint 2010

Microsoft SharePoint 2010 timer jobs perform much of the back-end work that is required to maintain your SharePoint farm. Timer jobs are executable tasks that run on one or more servers at a scheduled time. They can be configured to run exactly one time, or on a recurring schedule. They are similar to Microsoft SQL Server Agent jobs, which maintain a SQL Server installation by backing up databases, defragmenting database files, and updating database statistics. SharePoint uses timer jobs to maintain long-running workflows, to clean up old sites and logs, and to monitor the farm for problems. SharePoint also uses timer jobs to execute the logic of a solution deployment and feature activation. Depending on your edition of SharePoint and any installed third-party products, you can have many timer jobs in your farm, or just a few. Timer jobs have several advantages. They can run periodically and independently of users who are accessing your SharePoint sites, they can offload long-running processes from your web front-end servers, which increases the performance and responsiveness of your pages, and they can run code under higher privileges than the code in your SharePoint site and application pages.

You can view the timer jobs in your farm by using the Job Definitions page in SharePoint 2010 Central Administration. To access the Job Definitions page, click All Programs, Microsoft SharePoint 2010 Products, SharePoint 2010 Central Administration. On the Central Administration site, click the Monitoring link. Finally, click the Review Job Definitions link in the Timer Jobs section of the Monitoring page. The list of timer job definitions in your farm is displayed, as shown in Figure 1.

Figure 1. List of SharePoint timer job definitions

List of SharePoint timer job definitions

Because SharePoint timer jobs run in the background, they perform their tasks behind the scenes, even if no users are accessing your SharePoint sites. The Windows SharePoint Services Timer service runs the timer jobs in your farm. The service must be enabled and running on each server in your farm. The service enables the various SharePoint timer jobs to configure and maintain the servers in the farm. If you stop the Windows SharePoint Services Timer service on a server, you also stop all SharePoint timer jobs running on that server; for example, jobs that index your SharePoint sites, import users from Active Directory, and perform many other processes that affect the performance and usability of SharePoint.

Preparing to Create a SharePoint Timer Job

Before you can create your SharePoint timer job, you must install Microsoft Visual Studio 2010 (Professional, Premium, or Ultimate edition) on Windows Vista, Windows 7, or Windows Server 2008. SharePoint 2010 must be installed on the development computer.

After you install the required software, create a new SharePoint project in Visual Studio by selecting File, New, Project, which displays the New Project dialog box, shown in Figure 2. In the dialog box, ensure that .NET Framework 3.5 is selected in the drop-down list at the top of the dialog box, and expand the list of project templates in the left pane of the dialog box until 2010 is displayed under SharePoint. Select 2010 to display a list of SharePoint 2010 project templates in the right pane of the dialog box. Select Empty SharePoint Project from the list of templates, specify the project information at the bottom of the dialog box, and then click OK. You use the new project to develop your new timer job, package it for deployment to SharePoint, and then debug it.

Figure 2. New Project dialog box

New Project dialog box

Note

Your New Project dialog box might seem to be different from the dialog box shown in Figure 2, depending on your Visual Studio configuration.

Immediately after you click OK in the New Project dialog box, the SharePoint Customization Wizard dialog box appears, as shown in Figure 3. Type the URL of your SharePoint site in the text box, select Deploy as a farm solution, and then click Finish. You must select the Deploy as a farm solution radio button because timer jobs require a higher level of trust to execute than sandboxed solutions.

Figure 3. SharePoint Customization Wizard dialog box

SharePoint Customization Wizard dialog box

After you click Finish in the SharePoint Customization Wizard dialog box, Visual Studio creates and opens the project, as shown in Figure 4. Now that the project is created, you can start adding the classes that are required to form the basis of your SharePoint timer job. The next section outlines how to create those classes.

Figure 4. New SharePoint project open in Visual Studio

New SharePoint project open in Visual Studio

Creating a SharePoint Timer Job

All timer jobs, including those installed with SharePoint, are created and executed by using the SPJobDefinition class. To create a new SharePoint timer job, you must first add a class to your project that inherits from the SPJobDefinition class.

To add the class to your project

  1. Right-click the project and then choose Add, Class from the context menu to open the Add New Item dialog box.

  2. Specify a name for the class, and then click Add. Visual Studio opens the new class in the text editor.

  3. Change the visibility of the class to public, and make the class inherit from the SPJobDefinition class.

The following code snippet shows an example of a class that inherits from the SPJobDefinition class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;

namespace ArchiveFilesJob {
    public class ArchiveJob : SPJobDefinition {

        public ArchiveJob() : base() { }

        public ArchiveJob(string jobName, SPWebApplication webApp)
            : base(jobName, webApp, null, SPJobLockType.Job) {
            this.Title = jobName;
        }

        public override void Execute(Guid targetInstanceId) {
            // Put your job's code here.
        }
    }
}

In the code snippet, the ArchiveJob class inherits from the SPJobDefinition class, defines one non-default constructor, and overrides the Execute method of the base class. The non-default constructor is required because the default constructor of the SPJobDefinition class is for internal use only. When you create your constructor, you must pass the values for the four parameters described in Table 1 to the base class constructor.

Table 1. Parameters for the SPJobDefintion constructor

Name

Description

Name

The name of the job.

webApplication

An instance of the SPWebApplication class that owns this job.

Server

An instance of the SPServer class associated with this job. Pass null if this job is not associated with a specific server.

lockType

An SPJobLockType value that indicates the circumstances under which multiple instances of the job can be run simultaneously.

In the previous code snippet, null is passed as the value for server because this job is not associated with a specific server. SPJobLockType.Job is passed as the value for lockType to prevent SharePoint from running multiple instances of the job simultaneously. Table 2 lists the possible SPJobLockType values and their descriptions.

Table 2. SPJobLockType values

Value

Description

None

Locking is disabled. Job runs on all servers in the farm unless you pass an SPServer object for the server parameter.

ContentDatabase

Job runs for each content database that is associated with the job's web application.

Job

Only one server can run the job at a time.

After you create the constructors, you must override the Execute method of the SPJobDefinition class and replace the code in that method with the code that your job requires. If your code can run without further configuration, you are finished creating this class. Otherwise, you must add configuration screens and classes to your project, as shown in the next section. The next section also discusses the actual code from the sample that belongs in the Execute method.

Enabling Configuration for Your SharePoint Timer Job

To store configuration data for the job, create classes to contain that configuration and store it in SharePoint. First, the class must inherit from the SPPersistedObject class. Next, the fields in the class must be public, marked with the [Persisted] attribute, and have a data type that is either built-in (for example, Guid, int, string, and so on), inherits from SPAutoSerializingObject, or is a collection type that contains one of the built-in types or a type inheriting from SPAutoSerializingObject. Only fields are saved, not properties, as you might be used to when you serialize objects to XML. The following code snippet shows the two classes that are used to configure the ArchiveJob class.

using Microsoft.SharePoint.Administration;
public class ArchiveJobSettings : SPPersistedObject {
    public static string SettingsName = "ArchiveFilesJobSettings";

    public ArchiveJobSettings() { }
    public ArchiveJobSettings(SPPersistedObject parent, Guid id) 
        : base(SettingsName, parent, id) { }

    [Persisted]
    public Dictionary<Guid, SiteArchiveSettings> SiteArchiveSettings =
        new Dictionary<Guid, SiteArchiveSettings>();
}

public class SiteArchiveSettings : SPAutoSerializingObject {
    [Persisted]
    public Guid SiteCollectionId = Guid.Empty;
    [Persisted]
    public Guid SiteId = Guid.Empty;
    [Persisted]
    public Guid SourceDocLibId = Guid.Empty;
    [Persisted]
    public Guid DestinationDocLibId = Guid.Empty;
    [Persisted]
    public int MaxDays = 30;
    [Persisted]
    public bool Enabled = true;
}

In the code snippet, the ArchiveJobSettings class is used to configure the ArchiveJob class. It inherits from SPPersistedObject, and has a single field named SiteArchiveSettings that is marked with the [Persisted] attribute. The SiteArchiveSettings field enables the job to run for any number of sites in the same web application. The data type of the SiteArchiveSettings field is a Dictionary collection of SiteArchiveSettings objects, which is allowed because the Dictionary class is a collection, and contains SiteArchiveSettings objects that inherit from the SPAutoSerializingObject class.

One detail to note is that the ArchiveJobSettings class has two constructors defined; a default constructor, which is required for all serializable classes, and a second constructor that calls a constructor on its base class. This second constructor passes in the name of the SPPersistedObject object, an instance of an SPPersistedObject that acts as the parent of the ArchiveJobSettings object, and a Guid that is used to assign it a unique identifier in SharePoint. Because ArchiveJob is associated with a specific SPWebApplication object, the same SPWebApplication object becomes the parent of the ArchiveJobSettings object when it is saved to SharePoint. There is more information about how this works later in this section.

The SiteArchiveSettings class contains the site-specific settings for the ArchiveJob class. It inherits from SPAutoSerializingObject, and its fields follow the same rules as those for the SPPersistedObject class. The fields are marked with the [Persisted] attribute and are a built-in data type that enables them to be saved when the class is persisted to SharePoint.

After you create the classes for the job and its configuration, you can use the following code snippet to save the configuration of the job to SharePoint. Later, you add this code to an event handler that executes when the feature that contains your timer job is activated.

ArchiveJobSettings jobSettings = 
    new ArchiveJobSettings(webApplication, Guid.NewGuid());
// Be sure to change the URL below to one appropriate for your 
// environment.
using (SPSite siteCollection = new SPSite("http://local.demo.com")) {
    using (SPWeb site = siteCollection.RootWeb) {
        SiteArchiveSettings siteSettings = new SiteArchiveSettings();
        siteSettings.SiteCollectionId = site.Site.ID;
        siteSettings.SiteId = site.ID;
        siteSettings.SourceDocLibId = site.Lists["MyDocLib"].ID;
        siteSettings.DestinationDocLibId = 
            site.Lists["MyDocLibArchive"].ID;
        siteSettings.MaxDays = 30;
        siteSettings.Enabled = true;
        jobSettings.SiteArchiveSettings.Add(site.ID, siteSettings);
    }
}
jobSettings.Update(true);

In the code snippet, you create the configuration class ArchiveJobSettings by passing in an instance of the SPWebApplication class, which represents a SharePoint web application and a new Guid. After that, you configure the fields in the class. In the code snippet, a new instance of the SiteArchiveSettings class is created, configured, and then added to the SiteArchiveSettings field of the ArchiveJobSettings class.

When you are ready to save your configuration to SharePoint, call the Update method on your configuration class. Passing in true specifies that you want SharePoint to overwrite any existing saved configuration. Otherwise, an exception is thrown.

To retrieve your configuration, get an instance of the SPWebApplication, call its GetChild method, and then pass in the class type that you are retrieving, together with the name of the setting. The following code snippet shows part of the implementation of the Execute method of the SPJobDefinition-derived class.

public override void Execute(Guid targetInstanceId) {
    ArchiveJobSettings jobSettings =
        this.WebApplication.GetChild<ArchiveJobSettings>(
            ArchiveJobSettings.SettingsName);

    if (jobSettings == null) {
        return;
    }

    // Code omitted.
}

The ArchiveJobSettings class was retrieved from SharePoint by calling the GetChild method of the job's parent SPWebApplication. If nothing was previously saved to SharePoint, the call to the GetChild method returns null. After you have an instance of your job's configuration, the rest of the code in your Execute method can run.

Deploying Your Timer Job

Now that you have created the job and configuration classes, you must add a SharePoint feature to enable your SharePoint administrators to use the functionality in SharePoint. A SharePoint Feature is a set of provisioning instructions written in XML that specify what to do when the feature is activated. You can see a list of example features by clicking the Site Features or Site Collection Features link on the Site Settings page of your site.

To add a feature to your project

  1. Right-click the Features folder and choose Add Feature from the context menu.

    Figure 5. New feature added

    New feature added

  2. Type a user-friendly title and description in the top two text boxes. The values that you specify for the title and the description are displayed on the Web Application Features page in SharePoint Central Administration.

  3. Because this feature registers the job with one of the web applications in your farm, set the Scope to WebApplication.

  4. Click the Save button in the toolbar.

Now that you have created and configured the feature, you must add an event receiver to the feature so that you can add the code that is required to register your job. An event receiver is a class that runs code when certain events occur in SharePoint. In this case, you add an event receiver to run code when the feature is activated or deactivated. To add an event receiver, right-click your feature and then choose Add Event Receiver from the context menu.

After you add the event receiver, you must uncomment the FeatureActivated and FeatureDeactivating methods. You can remove the other methods because they are not used. Next, you must add code in the FeatureActivated method to register the job with SharePoint. Finally, you add code in the FeatureDeactivating method to unregister the job. The following code example shows how to register and unregister the ArchiveFilesJob object.

public override void FeatureActivated(
    SPFeatureReceiverProperties properties) {

    SPWebApplication webApplication = 
        (SPWebApplication)properties.Feature.Parent;

    // Remove job if it exists.
    DeleteJobAndSettings(webApplication);

    // Create the job.
    ArchiveJob job = new ArchiveJob(ArchiveJob.JobName, 
        webApplication);

    // Create the schedule so that the job runs daily, sometime between 
    // midnight and 4 A.M.
    SPDailySchedule schedule = new SPDailySchedule();
    schedule.BeginHour = 0;
    schedule.BeginMinute = 0;
    schedule.BeginSecond = 0;
    schedule.EndHour = 3;
    schedule.EndMinute = 59;
    schedule.EndSecond = 59;
    job.Schedule = schedule;
    job.Update();

    // Configure the job to archive files in a few sites in this web 
    // application.
    ArchiveJobSettings jobSettings = new ArchiveJobSettings(
        webApplication, Guid.NewGuid());
    using (SPSite siteCollection = 
        new SPSite("http://local.demo.com")) {
        SPWeb site = siteCollection.RootWeb;
        SiteArchiveSettings siteSettings = 
            new SiteArchiveSettings();
        siteSettings.SiteCollectionId = site.Site.ID;
        siteSettings.SiteId = site.ID;
        siteSettings.SourceDocLibId = 
            site.Lists["MyDocLib"].ID;
        siteSettings.DestinationDocLibId = 
            site.Lists["MyDocLibArchive"].ID;
        siteSettings.MaxDays = 30;
        siteSettings.Enabled = true;
        jobSettings.SiteArchiveSettings.Add(site.ID, siteSettings);

        // Add more sites here.
    }
    jobSettings.Update(true);
}

public override void FeatureDeactivating(
    SPFeatureReceiverProperties properties) {
    SPWebApplication webApplication = 
        (SPWebApplication)properties.Feature.Parent;

        DeleteJobAndSettings(webApplication);
}

private void DeleteJobAndSettings(SPWebApplication webApplication) {
    foreach (SPJobDefinition job in webApplication.JobDefinitions) {
        if (job.Name == ArchiveJob.JobName) {
            job.Delete();
            break;
        }
    }

    // Delete the job's settings.
    ArchiveJobSettings jobSettings =
        webApplication.GetChild<ArchiveJobSettings>(
            ArchiveJobSettings.SettingsName);
    if (jobSettings != null) {
        jobSettings.Delete();
    }    
}

In the code example, the FeatureActivated method gets an instance of the SPWebApplication class (for which this feature is being activated) by accessing the Feature property of the properties parameter. The Feature property returns an instance of the SPFeature class, which has a Parent property that you use to get an instance of the feature's parent. Table 3 lists the feature activation levels and the resulting type returned by the Parent property.

Table 3. Feature activation levels

Level

Type Returned

Farm

SPFarm

Web Application

SPWebApplication

Site Collection

SPSite

Site

SPWeb

Next, the FeatureActivated method calls the DeleteJobAndSettings method to remove the job if it already exists. The job might already exist if the feature was previously deployed but experienced a problem during deactivation. After that, an instance of the job definition is created by passing in the name of the job and an instance of the SPWebApplication class. After the job is created, you must set its Schedule property to an instance of one of the SPSchedule class types that are described in Table 4.

Table 4. SPSchedule class types

Type

Description

SPMinuteSchedule

Runs the job every x number of minutes. This class can be used to schedule jobs for periods of time other than hour, day, week, month, or year. For example, to run a job every 11 days, use this class and set its Interval property to 15840 minutes.

SPHourlySchedule

Runs the job every hour.

SPDailySchedule

Runs the job daily.

SPWeeklySchedule

Runs the job weekly.

SPMonthlySchedule

Runs the job monthly.

SPYearlySchedule

Runs the job yearly.

In the previous code example, the SPDailySchedule class is used to run the job daily. The properties that begin with Begin and End specify the earliest and latest time, respectively, that the job can start. The Timer service randomly selects a time during that interval to start the job. After you set the Schedule property of your job, call the Update method of the job to register it with SharePoint. The final step in the method is to create an instance of the ArchiveJobSettings class, set its properties, and then save it by calling its Update method.

In the FeatureDeactivating method, the DeleteJobAndSettings method is called to delete the previously registered job. The DeleteJobAndSettings method uses the JobDefinitions property to get a list of the jobs registered for that SPWebApplication object and deletes the job that the feature previously created. The method also gets the job's configuration and deletes it.

At this point, you are ready to test your code. In the next section, you learn how to test and debug your SharePoint timer job.

Testing and Debugging Your SharePoint Timer Job

When you debug SharePoint code, you typically set the build type of the project to debug, and then press F5 to debug the project. Visual Studio compiles your code, packages the resulting assembly and XML files into a SharePoint solution package (.wsp) file, and then deploys the solution package to SharePoint. After the solution package is deployed, Visual Studio activates the features that you created.

To debug the timer job

  1. To debug a timer job in SharePoint, you must attach to the process that is behind the SharePoint Timer Service. To attach to the SharePoint Timer Service, select Debug > Attach To Process from the menu bar.

  2. In the Attach To Process dialog box, ensure that the check boxes at the bottom of the dialog box are both selected, and then select OWSTIMER.EXE from the Available Processes list.

    Figure 6. Attach To Process dialog box

    Attach To Process dialog box

  3. Click Attach to finish attaching to the SharePoint Timer Service.

    Now you can add breakpoints in your job code.

To make the job run immediately, you can issue a Windows PowerShell command that causes the SharePoint Timer Service to run your job immediately. To open Windows PowerShell, click All Programs, click Microsoft SharePoint 2010 Products, and then choose SharePoint 2010 Management Shell.

The Windows PowerShell console opens with the SharePoint namespaces already registered.Type the following command on one line, and then press Enter to schedule your job for immediate execution.

Get-SPTimerJob "jobname" -WebApplication "url" | Start-SPTimerJob

In the command line, jobname is the name of your project and url is the URL of your web application. The Get-SPTimerJob command gets the job definition for your job, and the pipe (|) sends the job definition to the Start-SPTimerJob command, which in turn schedules it to run. The SharePoint Timer Service usually takes less than 30 seconds to finish running. If it does not execute, make sure that the debugger is not paused in Visual Studio.

Conclusion

Timer jobs give you the flexibility to offload your long-running or scheduled processes from your Internet Information Services (IIS) sites. Timer jobs are powerful because they can be configured to execute on a specific schedule and can include any functionality that you must have to create world-class, SharePoint-based solutions for your enterprise.

About the Author

Bryan Phillips is a senior partner at Composable Systems, LLC, and a Microsoft Most Valuable Professional in SharePoint Server. He is a co-author of Professional Microsoft Office SharePoint Designer 2007 and Beginning SharePoint Designer 2010 and maintains a SharePoint-related blog. Bryan has worked with Microsoft technologies since 1997 and holds the Microsoft Certified Trainer (MCT), Microsoft Certified Solution Developer (MCSD), Microsoft Certified Database Administrator (MCDBA), and Microsoft Certified Systems Engineer (MCSE) certifications.

The following were tech editors on Microsoft SharePoint 2010 articles from Wrox:

  • Matt Ranlett is a SQL Server MVP who has been a fixture of the Atlanta .NET developer community for many years. A founding member of the Atlanta Dot Net Regular Guys, Matt has formed and leads several area user groups. Despite spending dozens of hours after work on local and national community activities, such as the SharePoint 1, 2, 3! series, organizing three Atlanta Code Camps, working on the INETA board of directors as the vice president of technology, and appearing in several podcasts such as .Net Rocks and the ASP.NET Podcast, Matt recently found the time to get married to a wonderful woman named Kim, whom he helps to raise three monstrous dogs. Matt currently works as a senior consultant with Intellinet and is part of the team committed to helping people succeed by delivering innovative solutions that create business value.

  • Jake Dan Attis. When it comes to patterns, practices, and governance with respect to SharePoint development, look no further than Jake Dan Attis. A transplant to the Atlanta area from Moncton, Canada, Dan has a degree in Applied Mathematics, but is 100% hardcore SharePoint developer. You can usually find Dan attending, speaking at, and organizing community events in the Atlanta area, including code camps, SharePoint Saturday, and the Atlanta SharePoint User Group. When he's not working in Visual Studio, Dan enjoys spending time with his daughter Lily, watching hockey and football, and sampling beers of the world.

  • Kevin Dostalek has over 15 years of experience in the IT industry and over 10 years managing large IT projects and IT personnel. He has led projects for companies of all sizes and has participated in various roles including Developer, Architect, Business Analyst, Technical Lead, Development Manager, Project Manager, Program Manager, and Mentor/Coach. In addition to these roles, Kevin also managed a Solution Delivery department as a Vice President for a mid-sized MS Gold Partner from 2005 through 2008 and later also served as a Vice President of Innovation and Education. In early 2010 Kevin formed Kick Studios as a company providing consulting, development, and training services in the specialized areas of SharePoint and Social Computing. Since then he has also appeared as a speaker at numerous user group, summit, and conference type events across the country. You can find out more about Kevin on his blog, The Kickboard.

  • Larry Riemann has over 17 years of experience architecting and creating business applications for some of the world’s largest companies. Larry is an independent consultant who owns Indigo Integrations and does SharePoint consulting exclusively through SharePoint911. He is an author, writes articles for publication and occasionally speaks at conferences. For the last several years he has been focused on SharePoint, creating and extending functionality where SharePoint leaves off. In addition to working with SharePoint, Larry is an accomplished .Net Architect and has extensive expertise in systems integration, enterprise architecture and high availability solutions. You can find him on his blog.

  • Sundararajan Narasiman is a Technical Architect with Content Management & Portals Group of Cognizant Technology Solutions, Chennai, with more than 10 years of Industry Experience. Sundararajan is primarily into the Architecture & Technology Consulting on SharePoint 2010 Server stack and Mainstream .NET 3.5 developments. He has passion for programming and also has interest for Extreme Programming & TDD.

Additional Resources

For more information, see the following resources: