Featured
ASP.NET 6 Scheduling with Quartz.NET and Signalr Monitoring
Last modified: March 20, 2022In this article, we are going to use Quartz.NET to schedule our jobs and make use of Signalr to view monitoring the result/progress.
1. Create Project
Create an ASP.NET MVC application.
2. Install NuGet Package
- Microsoft.AspNetCore.SignalR.Client
- Microsoft.Extensions.Hosting
- Quartz
- Quartz.Extensions.Hosting
3. Install SignalR client library
@microsoft/Signalr@latest
4. Create SignalR js file
create a hub.js file and save to wwwroot->js folder
const connection = new signalR.HubConnectionBuilder().withUrl("/hub").build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
start();
connection.on("ConcurrentJobs", function (message) {
var li = document.createElement("li");
document.getElementById("concurrentJobs").appendChild(li);
li.textContent = `${message}`;
});
connection.on("NonConcurrentJobs", function (message) {
var li = document.createElement("li");
document.getElementById("nonConcurrentJobs").appendChild(li);
li.textContent = `${message}`;
});
5. HTML to display message
In the Index.cshtml, add below code to display messsage from SignalR
<div class="container">
<div class="row">
<div class="col-6">
<ul id="concurrentJobs"></ul>
</div>
<div class="col-6">
<ul id="nonConcurrentJobs"></ul>
</div>
</div>
</div>
<script src="~/microsoft/Signalr/dist/browser/signalr.js"></script>
<script src=~/js/hub.js></script>
7. Job Hub
Create a cs class file name JobsHub and replace with below code
public class JobsHub : Hub
{
//message used for concurrent job message
public Task SendConcurrentJobsMessage(string message)
{
return Clients.All.SendAsync("ConcurrentJobs", message);
}
//message used for nonconcurrent job message
public Task SendNonConcurrentJobsMessage(string message)
{
return Clients.All.SendAsync("NonConcurrentJobs", message);
}
}
8. Create Jobs
- ConconcurrentJob
Create a cs class file named ConconcurrentJob and replace with below code.
public class ConconcurrentJob : IJob
{
private static int _counter = 0;
private readonly IHubContext<JobsHub> _hubContext;
public ConconcurrentJob(IHubContext<JobsHub> hubContext)
{
_hubContext = hubContext;
}
public async Task Execute(IJobExecutionContext context)
{
var count = _counter++;
//start the job
var beginMessage = $"Conconcurrent Job BEGIN {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("ConcurrentJobs", beginMessage);
//we have long running job
Thread.Sleep(5000);
//complete the job
var endMessage = $"Conconcurrent Job END {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("ConcurrentJobs", endMessage);
}
}
Create a cs class file named NonConconcurrentJob and replace with below code.
public class ConconcurrentJob : IJob
{
private static int _counter = 0;
private readonly IHubContext<JobsHub> _hubContext;
public ConconcurrentJob(IHubContext<JobsHub> hubContext)
{
_hubContext = hubContext;
}
public async Task Execute(IJobExecutionContext context)
{
var count = _counter++;
//start the job
var beginMessage = $"Conconcurrent Job BEGIN {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("nonConcurrentJobs", beginMessage);
//we have long running job
Thread.Sleep(5000);
//complete the job
var endMessage = $"Conconcurrent Job END {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("nonConcurrentJobs", endMessage);
}
}
9. Program.cs
Add below code to Program.cs
builder.Services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionJobFactory();
var conconcurrentJobKey = new JobKey("ConconcurrentJob");
q.AddJob<ConconcurrentJob>(opts => opts.WithIdentity(conconcurrentJobKey));
q.AddTrigger(opts => opts
.ForJob(conconcurrentJobKey)
.WithIdentity("ConconcurrentJob-trigger")
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(5)
.RepeatForever()));
var nonConconcurrentJobKey = new JobKey("NonConconcurrentJob");
q.AddJob<NonConconcurrentJob>(opts => opts.WithIdentity(nonConconcurrentJobKey));
q.AddTrigger(opts => opts
.ForJob(nonConconcurrentJobKey)
.WithIdentity("NonConconcurrentJob-trigger")
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(5)
.RepeatForever()));
});
builder.Services.AddQuartzHostedService(
q => q.WaitForJobsToComplete = true);
builder.Services.AddSignalR();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<JobsHub>("/hub");
});