Update IIS bindings programmatically via SharePoint timer job

In some rare edge-cases, it may be necessary to programmatically update IIS settings from SharePoint code. In this example I’m updating the host header bindings in IIS as I’m using (and creating) host header site collections programmatically. I could use a wildcard DNS and the default port 80 but in my scenario we need explicit host header bindings.

To accomplish the update to IIS we need to use a timer job for two reasons. The first is to ensure our updates are run with sufficient privileges to perform the required updates – as timer jobs run under the farm account this is typically elevated enough already. Secondly, using the timer job framework allows us to target which servers (one, some or all) the modifications are run on. This is important  because  if we are using a farm with multiple servers, keeping changes to IIS bindings synchronised  across the farm is clearly a good place to aim for – in every other direction lies madness.

How to create a timer job is not in the scope of this post – here’s some great reference material to get you started: http://msdn.microsoft.com/en-us/library/cc427068(v=office.12).aspx – this example is for WSS 3 but the process is just the same in 2010.

The important thing to note is how you install your timer job. One of the parameters of your constructor method for the timer job can be an SPJobLockType :

image

The SPJobLockType enumeration has three members that control where the timer job is executed:

  • NoneProvides no locks. The timer job runs on every machine in the farm on which the parent service is provisioned, unless the job I associated with a specified server in which case it runs on only that server (and only if the parent service is provisioned on the server).
  • ContentDatabaseLocks the content database. A timer job runs one time for each content database associated with the Web application.
  • JobLocks the timer job so that it runs only on one machine in the farm.
    The None option is potentially the most useful option to us for updating IIS settings as this will cause the timer job to run on every server in the farm that is running the ‘Microsoft SharePoint Foundation Web Application’ service – these are effectively our web front end servers. This approach also relies on the third parameter passed to the constructor being null otherwise the SPServer object that is passed via this parameter is used as the server to host the timer job.

Once we’ve installed our timer job in the appropriate way, the payload is simple. We need to override the Execute method of our timer job with whatever logic we need. Here’s an extract of my code for updating IIS bindings which should now be executed of each SharePoint WFE:

image

I hope this helps….

Update: 23 December 2012 – A good friend of mine, Gael Fabry, pointed me in the direction of this article that describes the schema of the IIS 7 applicationHost.config file: http://msdn.microsoft.com/en-us/library/aa347559(v=VS.90).aspx

SPWorkItemJobDefinition – a different kind of SharePoint Timer Job.

I recently learnt about a new (well new to me at any rate) type of SharePoint timer job. Rather than the standard timer jobs I normally create that inherit from SPJobDefinition, this different kind of timer job inherits from SPWorkItemJobDefinition http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spworkitemjobdefinition.aspx

With a normal SharePoint timer job (SPJobDefinition), the job is scheduled via an SPSchedule object, and is run whenever this schedule dictates. When an occurrence of the timer job runs, any logic that is contained in the Execute method is then called:

image

So far, so normal. However, it is a fairly common requirement for a site collection to want a timer job to process something on its behalf – after all this what timer jobs excel at. However, communicating to the timer job what needs to be processed is usual done by creating custom list items (or some other content) in the site collection. Then the timer job has to iterate through the site content to find the items and then start performing some work based on those items or their properties.

I’ve done this myself and seen it done dozens of times and it usually involves hidden lists or custom columns on list items that the timer jobs is trained to look for.

Here’s where SPWorkItemJobDefinition timer jobs comes in. These timer jobs use a queue to determine what should be processed and the site collection simply adds items to the queue. No custom hidden lists, no custom columns, just a nice simple FIFO queue we can write too from the site collection Smile.

How it works

Create a timer job that inherits from SPWorkItemJobDefinition:

image

…override the WorkItemType property with a unique Guid of your choosing:

 image

…the WorkItemType is a unique Guid that this timer job will ‘listen’ for. Any operations that add SPWorkItems to the queue from the site collection will include a reference to this Guid. In this way, multiple timer jobs can share the same queue and SPWorkItems are picked up by the right timer jobs.

Next we override the ProcessWorkItem method, this is where we do our main processing and is the equivalent of the Execute method of a normal SPJobDefinition timer job: 

image

This method is called by the timer job framework on each occurrence of the timer job schedule AND ONLY IF work items have been queue for this timer job based on its WorkItemType Guid. Because this method is only called when items are queued for it and the method is passed the work items to process rather performing expensive queries looking for items within the site collection, this is potentially a much more efficient operation compared to a standard timer job!

Note: Checkout the ProcessWorkItems method if you want to process multiple items in a single method call

So far we’ve created a new SPWorkItemJobDefinition timer job, assigned it a unique WorkItemType and overridden the main timer job processing logic in the ProcessWorkItems method. Next, we’ll create a simple web part to add SPWorkItems to the scheduled work items queue. This is a simple operation but provides some great flexibility, the following code illustrates the properties of the SPSite.AddWorkItem method we will call:

image

…the properties we set on the SPSite.AddWorkItem method should be fairly obviously but I think the schdDateTime parameter that allows us to add an item to the queue but schedule it to processing at some future point in time and the rgbBinaryPayload byte array parameter are particularly interesting.

Once the timer job and web part are deployed, here’s how it functions; when the web part is added to a page it will generate a new work item with a unique Guid:

image

The results of the SPSite.AddWorkItem call can be seen in the dbo.ScheduledWorkItems table in the site collections content database:

image

…don’t go poking around in the database – I’m just illustrating the process. I’ve then set a break point on the ProcessWorkItem method of our timer job:

image

When our timer job schedule occurs, our ProcessWorkItems method is called (ONLY IF items are queued for it) and the work item we added in the site collection is available to us for processing.

I’m now off to refactor half the timer jobs I’ve ever written and remove lot’s of hidden lists and columns. Winking smile

If you want to download the solution I’m using in this article, it is available here: SPWorkItemJobDefinition.zip

I hope this helps…

Update SharePoint Timer Job Progress Programmatically

Often when developing custom timer jobs it can be very useful to provide feedback in central administration about the progress your job is making. Most of the out of the box timer jobs provide this progress feedback:

image

To extend your custom timer jobs to also support this progress bar is super easy with just one line of code:

image

The SPJobDefinition.UpdateProgress method is used to provide SharePoint with a percentage completeness of your timer jobs progress. The UpdateProgress method on SPJobDefinition takes a simple int parameter of a value between 0 and 100.

Now the hard part, how to calculate your actual (and accurate) progress value – you might find this article useful: http://en.wikipedia.org/wiki/Wikipedia:Reference_desk/Archives/Miscellaneous/2008_July_1#how_long_is_a_piece_of_string.3FWinking smile

Enjoy!