Housekeeping timer job that can dynamically load housekeepers

I have been toying with the idea of creating a general purpose timer job that can carry out any number of tasks now or in the future and that will not require re-compiling or redeployment. The solution I thought of was to dynamically load housekeeping assemblies using loose binding. Each housekeeper assembly exposes a simple interface with one method called DoWork. The assemblies do not need to be registered with the timer job. The timer job simply loads the assemblies that it finds in a specific folder and invokes their DoWork method. Here is the code.

We start with the HouseKeeper interface. This interface is assembled in a single file which is to be referenced by the timer job and housekeepers. The containing assembly is compiled for framework 3.5. All assemblies in the project where strongly named with the same key.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HouseKeeping
{
    public interface IHouseKeeper
    {
        void DoWork();
    }
}

Now for the timer job. This is the more complex part and I am only going to show the important executing class. You will also need to provide the feature and feature receiver.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using HouseKeeping;
using System.Reflection;
using System.IO;

namespace HouseKeeping
{
    public class JobOrchestrator : SPJobDefinition
    {

        private const string JOB_NAME = "HouseKeeping";

        public JobOrchestrator() : base() { }

        public JobOrchestrator(SPWebApplication webApp)
            : base(JOB_NAME, webApp, null, SPJobLockType.Job)
        {
            this.Title = JOB_NAME;
        }

        public override void Execute(Guid targetInstanceId)
        {

            // Get the housekeeper assemblies folder
            string houseKeeperFolder = SPUtility.GetLocalizedString("$Resources:HouseKeeperFolder", "HouseKeeping", 1033);

                 // Get the list of housekeeper assemblies
                 List<string>houseKeepers Directory.GetFiles(houseKeeperFolder, "TJHK*.dll").ToList<string>();

                 // get the house keepers that are going to do the work
                 houseKeepers.ForEach(hkDll=>{

                // Load the assembly
                Assembly assm = Assembly.LoadFrom(hkDll);

                //Enumerate the interfaces and look for the IHouseKeeper
                foreach (Type typ in assm.GetTypes())
                {
                    //Find the type that implements the IHouskeeper interface
                    Type[] interfaces = typ.GetInterfaces();
                    if (((IList<Type>)interfaces).Contains(typeof(IHouseKeeper)))
                    {
                        //Create an instance of the housekeeper
                        IHouseKeeper houseKeeper = Activator.CreateInstance(typ) as IHouseKeeper;

                        //Get the houseKeeper to do some work
                        houseKeeper.DoWork();
                    }
                }

            });
        }

    }
}

The final bit is to create the housekeeper assemblies that will be loaded when the timer job executes. I am going to show just one such assembly here. It must be compiled to an assembly name that starts with ‘TJHK’ and also must be strongly named.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.IO;
using Microsoft.SharePoint.Utilities;

namespace HouseKeeping
{
    public class CheckOut : IHouseKeeper
    {

        public void DoWork()
        {
                //Your implementation of the housekeeper goes here
        }
    }
}
This entry was posted in .NET Development, SharePoint, SharePoint 2007, SharePoint 2010, Tips and Tricks and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>