Create your own Timer Job

There may come a project where you'll need to fire off a task at certain schedules. Timer jobs are your answer. A timer job is code that is run at a specified shedule. In this post, I'll show you how to create an SPJobDefinition and how to programmatically deploy it.

The following example will use a timer job to copy items from a source list in one WebApplication and insert them into a list in another WebApplication without creating duplicates. There is some preliminary work that I won't be showing here involving serialization. I created an object that contained the source and destination list urls and also contained a list of fields from the source and their corresponding fields in the destination list. The result is the following xml file:


Let's start with the SPJobDefinition. You'll want to create a new class and inherit from the SPJobDefiniton (using Microsoft.SharePoint.Administration). The base class has 3 constructors. In the code below, you'll see that I have 4 constructors and that they're just being used to call the base constructors. Nothing special there.


Now, you'll need to override the Execute method as I have below. The first line deserializes the xml file that I showed you earlier. Basically, it takes my xml file and creates my FieldMapContainer object. Now, after that line is where the magic happens. I start by creating an SPSite object. The url used to instantiate the SPSite object contains the full url to the source list's allItems.aspx. The SPSite object is smart enough to take it apart and instantiate the object. The next line uses the same url and creates your SPList object. I do the exact smae with the destination list.

Next, you'll see a for loop that goes through each item in the source list. My destination list will contain the ID of each of these items in a field titled SourceID and since I don't want any duplicates, I'll write a caml query for each of these items. If the query doesn't find any items in the destination list that has a SourceID that matches the current item's ID, it will loop through my FieldMapContainer's list of fieldmappings and assign the source list field values to the newItem. If it finds a match, it will not create an item in the destination list.


There are several ways to run start the job. In this example, I chose to write a console app to do this. Another method would be to create a feature receiver. You'll see that once I instantiate my DataCopyJob object (I know, awful name), I loop through all existing JobDefinitions and if I find one with the name of my current job, it get's deleted. I then create an SPMinuteSchedule object that will define how often the object is run and I assign it to the job's schedule property and update the job.



Take a look at my source List



The timer job will look at the Articles list (which is in a different web application), and if it doesn't find the item, a copy is added to the list. You'll see a 3rd column in the image below. That SourceID column contains the source items ID.



This was a very quick demo (the code in the execute method could be much better) but you should be able to see how timer jobs are useful. If the source list was very long, it would take a long time for the code to loop through each item then query the destination list for each item individually. A timer job is useful in this situation because you can schedule it to run nightly, without you having to worry about slowing down the system during working hours.

Labels: