Implementing Scheduled Tasks in ASP.NET WebAPI using Quartz.Net

Introduction

While basic timer mechanisms can handle simple periodic operations, enterprise-level applications often require a more robust framework for managing complex background jobs. Quartz.Net is a powerful, open-source job scheduling library ported from the Java Quartz framework. It allows developers to reliably execute tasks such as email dispatches, data synchronization, and system maintainance without relying on external tools like the Windows Task Scheduler. This guide demonstrates how to integrate Quartz.Net into an ASP.NET WebAPI project to manage recurring jobs efficiently.

Installation

To get started, install the Quartz.Net library via the NuGet Package Manager. In your WebAPI project, run the following command in the Package Manager Console:

Install-Package Quartz

This installation automatically adds the necessary dependencies, inlcuding the core Quartz library and required logging adapters.

Creating a Scheduled Job Programmatically

In this example, we will create a job that sends a notification email every 30 minutes.

1. Defining the Job Logic

First, define the business logic that needs to be executed. Here, we encapsulate the email sending logic within an asynchronous method.

public async Task<int> SendNotificationAsync()
{
    int statusCode = 0;
    try
    {
        var emailDetails = new EmailMessage
        {
            Recipient = "user@example.com",
            Subject = "System Notification",
            Body = "This is an automated scheduled message.",
            SenderCredentials = "password"
        };
        
        // Assume EmailService is a helper class for sending emails
        EmailService.Send(emailDetails);
    }
    catch (Exception ex)
    {
        // Log exception details here
        statusCode = -1;
    }
    return await Task.FromResult(statusCode);
}

2. Implementing the Job Interface

Create a class that implements the IJob interface provided by Quartz. The Execute method contains the code that runs when the trigger fires.

using Quartz;
using Quartz.Impl;

public class NotificationJob : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        // Invoke the business logic
        return SendNotificationAsync();
    }
}

3. Configuring the Scheduler

The scheduler is responsible for coordinating jobs and triggers. The following class sets up a scheduler that runs the NotificationJob every 30 minutes.

public class SchedulerSetup
{
    public static void Initialize()
    {
        // 1. Create the scheduler factory
        ISchedulerFactory factory = new StdSchedulerFactory();
        
        // 2. Get a scheduler
        IScheduler scheduler = await factory.GetScheduler();

        // 3. Define the job and link it to our NotificationJob class
        IJobDetail jobDetail = JobBuilder.Create<NotificationJob>()
            .WithIdentity("emailNotification", "group1")
            .Build();

        // 4. Define the trigger (run every 30 minutes)
        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity("trigger1", "group1")
            .StartNow()
            .WithSimpleSchedule(x => x
                .WithIntervalInMinutes(30)
                .RepeatForever())
            .Build();

        // 5. Schedule the job
        await scheduler.ScheduleJob(jobDetail, trigger);

        // 6. Start the scheduler
        await scheduler.Start();
    }
}

4. Starting the Scheduler on Application Startup

To ensure the scheduler starts when the application launches, call the initialization method in Global.asax.cs.

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        // Standard WebAPI registration
        GlobalConfiguration.Configure(WebApiConfig.Register);
        
        // Initialize the Quartz scheduler
        SchedulerSetup.Initialize();
    }
}

Configuring Jobs via XML

Hardcoding schedules in C# requires recompiling the application to change intervals. Quartz.Net supports XML-based configuration, allowing you to modify schedules externally.

1. Update Web.config

Add the configuration section handler and the Quartz-specific settings to your Web.config file.

<configSections>
  <section name="quartz" type="System.Configuration.NameValueSectionHandler"/>
</configSections>

<quartz>
  <add key="quartz.scheduler.instanceName" value="DefaultQuartzScheduler"/>
  <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz"/>
  <add key="quartz.threadPool.threadCount" value="10"/>
  <add key="quartz.jobStore.type" value="Quartz.Simpl.RAMJobStore, Quartz"/>
  
  <!-- XML Plugin configuration -->
  <add key="quartz.plugin.xml.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz" />
  <add key="quartz.plugin.xml.fileNames" value="~/quartz_jobs.xml"/>
</quartz>

2. Create quartz_jobs.xml

Create a file named quartz_jobs.xml in your project root. This file defines the job and its schedule using a Cron expression.

<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" 
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                      version="2.0">
  <schedule>
    <!-- Job Definition -->
    <job>
      <name>EmailNotificationJob</name>
      <group>NotificationGroup</group>
      <description>Sends periodic emails</description>
      <job-type>WebAPI.Utilities.NotificationJob, WebAPI</job-type>
      <durable>true</durable>
      <recover>false</recover>
    </job>

    <!-- Trigger Definition using Cron -->
    <trigger>
      <cron>
        <name>IntervalTrigger</name>
        <group>NotificationGroup</group>
        <description>Runs every 30 minutes</description>
        <job-name>EmailNotificationJob</job-name>
        <job-group>NotificationGroup</job-group>
        <!-- Cron expression: 0 seconds, 0-30 minutes, every hour, every day -->
        <cron-expression>0 */30 * * * ?</cron-expression>
      </cron>
    </trigger>
  </schedule>
</job-scheduling-data>

3. Simplify the Scheduler Code

With the configuration moved to XML, the C# scheduler code simplifies to just starting the scheduler.

public class SchedulerSetup
{
    public static async Task Initialize()
    {
        ISchedulerFactory factory = new StdSchedulerFactory();
        IScheduler scheduler = await factory.GetScheduler();
        
        // The XML plugin will load the jobs and triggers automatically
        await scheduler.Start();
    }
}

Advanced Usage with Cron Expressions

For complex scheduling requirements, Cron triggers are preferred over simple interval triggers. A Cron expression consists of seven fields: seconds, minutes, hours, day of month, month, day of week, and year (optional).

Cron Expression Syntax

Field Allowed Values Special Characters
Seconds 0-59 , - * /
Minutes 0-59 , - * /
Hours 0-23 , - * /
Day of Month 1-31 , - * ? / L W
Month 1-12 or JAN-DEC , - * /
Day of Week 1-7 or SUN-SAT , - * ? / L #
Year (Optional) 1970-2099 , - * /

Special Characters Explained

Character Description
* Wildcard (matches all values). e.g., "*" in minutes means "every minute".
? No specific value (used for Day of Month and Day of Week).
- Range. e.g., "10-12" in hours means 10, 11, and 12.
, List. e.g., "MON,WED,FRI" for Monday, Wednesday, Friday.
/ Increment. e.g., "0/15" in seconds means every 15 seconds starting at 0.
L Last. "L" in Day of Month means the last day of the month.
W Weekday. Nearest weekday to the given date.
# Nth X day of the month. e.g., "6#3" is the third Friday.

Cron Expression Examples

Expression Meaning
0 0 12 * * ? Fire at 12:00 PM every day.
0 15 10 ? * * Fire at 10:15 AM every day.
0 0/5 14 * * ? Fire every 5 minutes starting at 2:00 PM and ending at 2:55 PM, every day.
0 15 10 ? * MON-FRI Fire at 10:15 AM, Monday through Friday.
0 15 10 15 * ? Fire at 10:15 AM on the 15th day of every month.
0 15 10 L * ? Fire at 10:15 AM on the last day of every month.
0 0 12 1/5 * ? Fire at 12:00 PM, every 5 days starting on the 1st of the month.

Logging

Monitoring job execution is critical for maintenance. Quartz.Net utilizes Common.Logging for internal operations. Developers can integrate this with frameworks like Log4Net or NLog to persist execution logs to files or a database for auditing and debugging purposes.

Tags: ASP.NET WebAPI quartz.net Job Scheduling Cron expressions C#

Posted on Thu, 27 Aug 2026 16:32:15 +0000 by AVATAr