Have you ever thought about doing something in the background to make your request shorter, but kept getting exceptions saying that the DbContext is disposed?
Here is the solution
Hangfire is an open-source framework for .NET that offers a straightforward approach to execute background tasks within your application. It enables the asynchronous execution of jobs and the ability to schedule them to run either at a designated time or on a recurring basis.
Firstly, install the following nuget packages
Then configuration, I assume you are at least junior .NET devleoper and know basic configuration in Program.cs
public interface IFakeEmailSenderBackgroundJob
{
Task Send(string message, string title, string destinationEmail);
}
public class FakeEmailSenderBackgroundJob : IFakeEmailSenderBackgroundJob
{
public async Task Send(string message, string title, string destinationEmail)
{
await File.WriteAllTextAsync($"mails.txt", $"{title}\t{message}\t{destinationEmail}\n");
}
}
I’ve created simple fake email sender which is saving to file sent mails.
Create SQL Server database named “Hangfire-db”, and then add the following configuration
builder.Services.AddHangfire(x =>
x.UseSqlServerStorage("Data Source=localhost;Initial Catalog=Hangfire-db;Integrated Security=true;TrustServerCertificate=true;"));
builder.Services.AddHangfireServer();
builder.Services.AddScoped<IFakeEmailSenderBackgroundJob, FakeEmailSenderBackgroundJob>();
in the app section
app.UseHangfireDashboard();
It’s web api project, so let’s create sample endpoint which will be using our FakeEmailSenderBackgroundJob
app.MapPost("/send-mail", (string message, string title, string destinationEmail) =>
{
return BackgroundJob.Schedule<IFakeEmailSenderBackgroundJob>(x =>
x.Send(message, title, destinationEmail),
DateTimeOffset.Now.AddMinutes(1)
);
})
.WithName("SendMail")
.WithOpenApi();
As you can understand from this code, the endpoint will schedule the sending of the email to occur one minute after the endpoint is executed.
You can go to the /hangfire url in your application and then you should see Hangfire dashboard.
Send two requests and see what happens.
We can see that our job is scheduled correctly
Here are the details regarding our enqueued job.
Wait for a one minute.
The enqueued job has been executed, and as we can see, the result is correct. You can perform any desired operations inside your job class. As mentioned earlier regarding the disposed DbContext, you can inject your DbContext or repository directly into the job class.
How about failed tasks?
Let’s change the implementation of the FakeEmailSenderBackgroundJob to the following
public class FakeEmailSenderBackgroundJob : IFakeEmailSenderBackgroundJob
{
public async Task Send(string message, string title, string destinationEmail)
{
throw new Exception();
await File.WriteAllTextAsync($"mails.txt", $"{title}\t{message}\t{destinationEmail}\n");
}
}
Let’s check our dashboard now.
Let’s wait a minute and check again.
Here’s an interesting observation: the Hangfire job failed to complete successfully and raised an exception, resulting in the job being requeued. Hangfire attempted to execute the job again, with the default behavior allowing for 10 attempts.
We can read number of attempts from information container with blue background
As you can see, Hangfire attempted to execute its job 10 times before marking it as Failed.
Below you can see failed jobs tab
What else Hangfire can do?
Fire-and-Forget Jobs – This job is executed immediately after we execute our method associated with it. Background jobs are useful when you have a large task that consumes a lot of time, and it’s better to perform it asynchronously in the background.
Recurring Jobs – We can set up a cron expression to determine when tasks will be triggered. This is useful, for example, in a SaaS application where we need to check daily if a user has a valid subscription, and if not, suspend it. Similarly, in an application for lawyers, we might want to display court dates with deadlines 10 days in advance. In this case, it’s beneficial to have a background job executed daily that marks important cases. These are just a few examples; there are many other situations where a recurring job would be useful.
Delayed Jobs – We used it in our example. You can set a DateTimeOffset with a delay after which the task will be processed.
Continuations – We can execute a job when its parent job finishes. This is useful when we want to create a pipeline of task execution, especially when certain data needs to be created or prepared beforehand.
Hangfire has more paid options, but I don’t think they are necessary for standard purposes
Somebody essentially lend a hand to make significantly posts I might state. That is the very first time I frequented your web page and up to now? I surprised with the research you made to create this particular put up amazing. Excellent job!