Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Quartz.Net - Custom Base Job

5.00/5 (4 votes)
7 Jun 2012CPOL1 min read 42.5K  
Creating a custom base job class for quartz scheduler development

Introduction 

Quartz.Net allows you to schedule jobs to run. These jobs are often configured with variables from a JobDataMap object. I wanted a simple and effective class that will allow me to use .NET properties instead of relying on configuring and setting up a JobDataMap when I needed to schedule a job.

Background 

An important aspect that I wanted to address was that although the Quartz.Net JobDataMap class will allow you to store objects, I only wanted to store string values. The problem is that if you store .net objects in the JobDataMap, you will also run the risk of running into type or versioning issues.

Taking advantage of the Json.NET framework, I built a simple QuartzJobBase class that allowed me to only store string values but also allow me to store more complex objects in the JobDataMap.

Using the code   

Before you start, make sure you are referencing the Json.NET assembly.

The QuartzJobBase class is an abstract implementation of a Quartz.Net job. It is in charge of 3 important aspects.

  1. Serializing current property values into a JobDataMap
  2. Deserializing property values from a JobDataMap
  3. Wrapping exceptions thrown by implementations with a JobExecutionException.

To seralize proeprty values in a JobDataMap, you can simple call  BuildJobDataMap() on your object to build a JobDataMap instance with your current property values.

Deserializing the object is being handled automatically by the class because it is executed when the job is executed by the Quartz scheduler.

using System;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;

namespace Quartz.Custom
{
    public abstract class QuartzJobBase : IJob
    {
        private static readonly Newtonsoft.Json.JsonSerializerSettings JsonSettings;
        static QuartzJobBase()
        {
            JsonSettings = new JsonSerializerSettings();
            JsonSettings.TypeNameHandling = TypeNameHandling.Auto;
            JsonSettings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
        }

        public void Execute(IJobExecutionContext context)
        {
            try
            {
                ReadFromJobDataMap(context.MergedJobDataMap);
                InternalExecute(context);
            }
            catch (Exception ex)
            {
                // Jobs should throw JobExecutionException if error occurred.
                // Wrap internal exceptions with JobExecutionException.
                JobExecutionException jex = new JobExecutionException(ex);
                throw jex;
            }
        }
        protected abstract void InternalExecute(IJobExecutionContext context);

        #region JobDataMap & Serialization
        
        public JobDataMap BuildJobDataMap()
        {
            JobDataMap data = new JobDataMap();

            foreach (var prop in GetType().GetProperties())
            {
                object value = prop.GetValue(this, null);
                string s = GetPropertyValue(prop);
                data.Add(prop.Name, s);
            }

            return data;
        }
        private void ReadFromJobDataMap(JobDataMap data)
        {
            PropertyInfo[] properties = GetType().GetProperties();

            foreach (var key in data.Keys)
            {
                var p = properties.Where(x => x.Name == key).SingleOrDefault();

                if (p != null)
                {
                    SetPropertyValue(p, data.GetString(key));
                }
            }
        }

        private string GetPropertyValue(PropertyInfo property)
        {
            object value = property.GetValue(this, null);
            return JsonConvert.SerializeObject(value, Formatting.None, JsonSettings);
        }
        private void SetPropertyValue(PropertyInfo property, string value)
        {
            object obj = JsonConvert.DeserializeObject(value, property.PropertyType, JsonSettings);
            property.SetValue(this, obj, null);
        }

        #endregion
    }
}

A sample job implementation would look like this.  

public class HelloWorldJob : QuartzJobBase
   {
       public string Name { get; set; }
       public int FavoriteNumber { get; set; }
       public List<string> CustomList { get; private set; }

       public HelloWorldJob()
       {
           CustomList = new List<string>();
       }

       protected override void InternalExecute(Quartz.IJobExecutionContext context)
       {
           Console.WriteLine("Hello World from {0} ({1})", Name, FavoriteNumber);

           foreach (var item in CustomList)
           {
               Console.WriteLine("{0} CUSTOM LIST: {1}", Name, item);
           }
       }
   }

To schedule a job by providing a JobDataMap

HelloWorldJob j = new HelloWorldJob();
j.Name = "My Name";
j.FavoriteNumber = r.Next(100);
for (int x = 0; x < 10; x++)
{
    j.CustomList.Add(r.Next().ToString());
}                

sched.ScheduleJob(
    JobBuilder.Create(typeof.HellowWorldJob)
    .UsingJobData(j.BuildJobDataMap())
    .Build(),
    TriggerBuilder.Create()
    .StartNow()
    .Build());

Enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)