Combining Blazor Plugins With Quartz Jobs – Dev Leader Weekly 29

Welcome to Dev Leader Weekly!

TL;DR:

  • I’m trimming up my newsletter. Most issues have taken me ~4-6 hours and it’s not sustainable. They’ll be more streamlined.
  • The coding challenges are moving to my Discord community. They’ll run on a 3-week rotation.
  • I’ve launched loyalty rewards so you can earn chances for future giveaways. I’ll add to how you can earn, including submitting coding challenges!
  • I’m working on TWO Dometrain courses right now. These will be released in a couple of months.

If you enjoy my content, you’ll love premium membership access to my site! This includes:

Let’s dive in!


What’s In This Issue


Blazor Plugins for Quartz Jobs

Where We Left Off With Quartz

If you’ve been following along in the Blazor build series, then you’ll know that in the last update, we reached a point in our plugin API design where we hit a bit of a roadblock. Originally, I had suggested that we might be able to work with a plugin facade, and this would allow us to hide the fact we have many plugins and then ask to query for the relevant data all at once through a common interface. However, this would fall apart when we started to look at Quartz and how to set it up.

Here’s what things were looking like where we last left off:

Blazor Plugins with Quartz Job Scheduler - Old Relationship

In the picture above, we have Quartz inside of the Blazor app and then a Facade layer that sits in front of the plugins. That meant that the one Quartz job we’d go to create would (unknowingly) go pull data from each plugin. To the job, it only looks like one data fetching API thanks to the facade.

The Quartz API Constraints

After getting Quartz dropped in and checking out what we had to work with, it made a lot more sense to consider a job that could be scheduled for each plugin. This meant that instead of the plugin API strictly providing an interface for fetching data, it could expose some job information. However, the way that we needed to load that into Quartz was feeling awful due to the plugin needing to expose a type object.

And… that’s gross for a couple of reasons:

  • It’s just a type object! There’s no enforcement at compile time as to what type it will refer to so it would be easy to do incorrectly.
  • It meant that the plugins would need to know about Quartz because the type they expose would need to be an IJob from Quartz.

These two things alone were enough for me to want to move away from the paradigm we started with.

The New Plugin Relationship

With these constraints in mind, going to a 1:1 relationship of Quartz job to plugin made more sense. But it wasn’t going to be without its challenges. Here’s what I wanted the new relationship to look like instead, where we resolve from the dependency container and skip the facade:

Blazor Plugins with Quartz Job Scheduler - 1 to 1

This meant that we did away with the facade class altogether and the plugins would no longer need to expose a gross API like this:

public sealed record SocialJobProvider(
    string JobTypeId,
    Type JobType, // FIXME: this is so gross :(
    TimeSpan Interval);

But instead, we could move towards this:

public sealed record SocialJobProvider(
    string JobTypeId,
    ISocialDataFetcher DataFetcher,
    TimeSpan Interval);

This is much closer to what we started with where a plugin just implemented an ISocialDataFetcher.

Dependency Injection & Job Scheduling

These two things had to change up a little bit from what I expected in the beginning — but I should have anticipated some change. I came from using Autofac for all of my dependency injection and wanted to ensure I could focus on the built-in dotnet DI framework. As a result, I had to move the job scheduling logic to be later than I anticipated, but the DI code is still pretty simple:

builder.Services.AddSingleton<TwitterDataFetcher>();
builder.Services.AddSingleton(x => new TwitterConfig(
    "Consumer Key Here",
    "Consumer Secret Here",
    "DevLeaderCA"));
builder.Services.AddSingleton(x => new SocialJobProvider(
    "Twitter",
    x.GetRequiredService<TwitterDataFetcher>(),
    TimeSpan.FromHours(1)));

I’ll need to adapt this to pull from other assemblies later on — but I haven’t done this yet for the built-in framework. I have extensive experience with this in Autofac, but we’ll cross that bridge when we get there!

As for the job scheduling, I can resolve all of the SocialJobProvider instances that come off of the DI framework and schedule jobs with the following code:

var schedulerFactory = app.Services.GetRequiredService<ISchedulerFactory>();
var quartz = await schedulerFactory.GetScheduler();
foreach (var socialJobProvider in app
    .Services
    .GetRequiredService<IEnumerable<SocialJobProvider>>())
{
    var jobKey = new JobKey(socialJobProvider.JobTypeId);
    var jobDetail = JobBuilder
        .Create<FetchingJob>()
        .SetJobData(new JobDataMap
        {
            [nameof(ISocialDataFetcher)] = socialJobProvider.DataFetcher
        })
        .WithIdentity(jobKey)
        .Build();
    var jobTrigger = TriggerBuilder
        .Create()
        .WithIdentity(socialJobProvider.JobTypeId + "-trigger")
        .WithSimpleSchedule(x => x
            .WithInterval(socialJobProvider.Interval)
            .RepeatForever())
        .Build();
    await quartz.ScheduleJob(jobDetail, jobTrigger);
}

Next Steps in Our Blazor App

The next steps are going to include wiring up Entity Framework! We’re at the point where we can likely pull Twitter data if we have the authentication properly configured, but we don’t have a spot to store it. I think it will be helpful for us to spec out some thoughts about what we need to store and how to store it so we can work on extending our prototype.

If you want to see a video walkthrough of this article, check out this early-access video here:

YouTube player

Unlock the Power of Quartz Job Scheduler in ASP.NET Core Blazor

YouTube player

In our ASP.NET Core Blazor build series, we’ve discussed the need for a dotnet job scheduler. Lucky for us, we can use Quartz for C# which allows us to schedule jobs! Join me as we explore building our ASP.NET Core Blazor web app and experiment with integrating Quartz .NET for job scheduling!

Avoid This Collaboration KILLER In Software Engineering

YouTube player

As a developer, it’s important to focus on your ability to collaborate. This is especially important because, in software engineering, we’re focused on solving problems… And the most effective way that we do that is by working in teams. Check out this video for advice on how to avoid killing collaboration. This is especially important as a more senior software engineer!

Epic Fail or Promising Attempt – Auto Pipeline Config in C#

YouTube player

The pipeline design pattern is an awesome way for us as C# developers to be able to process data. We can configure stages to wire up and pass data from one to the next. However, one of the challenges is setting this design pattern up! Nobody wants to configure it by hand… Will this thought experiment lead to an easier way for us to configure pipelines in dotnet?

Informal Leadership in Software Engineering – What You Need To Progress

Informal Leadership in Software Engineering - What You Need To Progress

Informal leadership in software engineering is a critical part of becoming more senior in your role. But what’s involved and why is it so beneficial?

The Memento Pattern in C# – How to Achieve Effortless State Restoration

The Memento Pattern in C# - How to Achieve Effortless State Restoration

Looking to implement the Memento Pattern in C#? Learn about its origin and principles, and the different components & steps to implementation!

You’re Killing Collaboration (And How To Fix It)

You're Killing Collaboration (And How To Fix It)

Are you killing collaboration on your software engineering teams when it comes to problem-solving? Don’t multiply a negative impact! Let’s fix it.

Custom Middleware in ASP.NET Core – How to Harness the Power!

Custom Middleware in ASP.NET Core - How to Harness the Power

Learn about different types of middleware and how to implement custom middleware in ASP.NET Core to solve common challenges in web development!

Ultimate Starter Guide to Middleware in ASP.NET Core: Everything You Need to Know

Ultimate Starter Guide to Middleware in ASP.NET Core: Everything You Need to Know

Discover the benefits of middleware in ASP.NET Core, including flexibility and modularity. Learn about middleware like authentication and logging!


As always, thanks so much for your support! I hope you enjoyed this issue, and I’ll see you next week.

​Nick “Dev Leader” Cosentino
[email protected]

Socials:
Blog
Dev Leader YouTube
Follow on LinkedIn
Dev Leader Instagram

P.S. If you enjoyed this newsletter, consider sharing it with your fellow developers. Let’s grow our community together!

author avatar
Nick Cosentino Principal Software Engineering Manager
Principal Software Engineering Manager at Microsoft. Views are my own.