Thoughts on simple code for scheduling using Hangfire in an ASP.NET Core (minimal) project

I’m learning about both ASP.NET Core (migrating from long-time ASP.NET Framework development) and Hangfire. I have a small-scale test project working, based on lots of reading in Hangfire documentation and forum and other sources. Please feel free to comment/critique any of this, or offer suggestions for changes, improvements, or even completely different approaches.

This is related to my earlier post “example of setting up a .NET 8 (Core) Razor/minimal Web app with Hangfire”, and builds on that project.

Please feel free to reply/comment if you have alternative suggestions or approaches, or if there are any errors in the following.

This is a small example of creating application code (classes) in an ASP.NET Core web application (.NET 6.0 or later) using the Razor “minimal” style (no Startup.cs file, only Program.cs - using top-level statements) and SQL Server. This topic assumes that you have already set up Hangfire in your ASP.NET Core project.

In the “appsettings.json” (and the corresponding “Development” version of the file), I’m adding a “ConnectionStrings” section and an “EmailSettings” section to be used in this example.

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "HangfireDBConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HangfireLocal;Integrated Security=SSPI;",
    "TestDBConnection": "Server=(localdb)\\MSSQLLocalDB;Database=TestDBLocal;Integrated Security=SSPI;"
  },
  "EmailSettings": {
    "ServerAddress": "smtp.servername.com",
    "ServerPort": 25,
    "ServerUseSsl": false,
    "SmtpUsername": "",
    "SmtpPassword": "",
    "FromName": "Email Name",
    "FromAddress": "email@example.com",
    "ToEmail": "",
    "CcEmail": "",
    "BccEmail": ""
  }
}

Create the Hangfire database if it doesn’t already exist (I’m using a local DB in this example) - run SSMS (SQL Server Management Studio), connect to database engine “(localdb)\MSSQLLocalDB” and create a new empty database named “HangfireLocal” (the database name in the Hangfire connection string above). Or, create the Hangfire database in your preferred SQL Server instance, and change the connection strings to match in appsettings.json.

Note that if you are connecting to a SQL Server database (version 2019 or later), the connection string will likely be something like this for .ENT Core (with “tcp:” before the server/instance name for TCP connections, and with “Encrypt=False” unless you are enforcing encrypted connections to SQL Server):
"Data Source=tcp:SQLSERVERNAME\\SQLINSTANCE;Initial Catalog=TestDB;User ID=USERNAME;Password=PASSWORD;Connect Timeout=30;Application Name=HANGFIRE;Encrypt=False;"

In your ASP.NET Core web project, create a folder for your code/class files. I use a folder named “Code”. In this folder, create a class file for ConnectionStrings and for EmailSettings, similar to:

//ConnectionStringSettings.cs
namespace HangfireProject.Code
{
    public class ConnectionStringSettings
    {
        public string? HangfireDBConnection { get; set; }
        public string? TestDBConnection { get; set; }
    }
}
//EmailSettings.cs
namespace HangfireProject.Code
{
    public class EmailSettings
    {
        public string? ServerAddress { get; set; }
        public int ServerPort { get; set; }
        public bool ServerUseSsl { get; set; }
        public string? SmtpUsername { get; set; }
        public string? SmtpPassword { get; set; }
        public string? FromName { get; set; }
        public string? FromAddress { get; set; }
        public string? ToEmail { get; set; }
        public string? CcEmail { get; set; }
        public string? BccEmail { get; set; }
    }
}

Then, in the Program.cs file, add code to configure the 2 classes above from the corresponding sections in appsettings.json (after “CreateBuilder” and before “AddRazorPages”):

var builder = WebApplication.CreateBuilder(args);
[...]
builder.Services.Configure<EmailSettings>(builder.Configuration.GetSection("EmailSettings"));
builder.Services.Configure<ConnectionStringSettings>(builder.Configuration.GetSection("ConnectionStrings"));
[...]
builder.Services.AddRazorPages();
var app = builder.Build();

Next, create a class (also in the “Code” folder) that you want to schedule with Hangfire - “SampleClass.cs” here:

using Microsoft.Extensions.Options;
namespace Hangfire.Code
{
    public class SampleClass(ILogger<SampleClass> logger, IOptions<ConnectionStringSettings> connSettings, IOptions<EmailSettings> emailSettings)
    {
        private readonly ILogger<SampleClass> _logger = logger;
        private readonly ConnectionStringSettings _connSettings = connSettings.Value;
        private readonly EmailSettings _emailSettings = emailSettings.Value;

        public void Method1(string param1, string param2)
        {
			// Use any of the properties on the Options objects, for example:
			string _serverAddress = _emailSettings.ServerAddress;
			string _testDBconnection = _connSettings.TestDBConnection;
            [...]
			// call method with parameters _serverAddress, _testDBconnection, etc.
        }
        public void Method2(string param1, string param2, int param3)
        {
            [...]
        }
    }
}

Note: I have seen some sample code that uses “async” methods here, but I’m keeping it simpler. Since the methods are run later by the Hangfire scheduler, I’m not sure there is a lot of benefit to making the methods “async”.

In Program.cs (or in code called from Program.cs) before "“app.Run()”, schedule the method as either of (for example):

BackgroundJob.Enqueue<SampleClass>(p => p.Method1("str1", "str2"));
RecurringJob.AddOrUpdate<SampleClass>("MyJobName", p => p.Method1("str1","str2"), Cron.Hourly());

As I mentioned at the start, let me know if you have any criticisms or suggestions for any of the above.