Software Development

HangFire simplifies job processing and fills gap in .NET development

The open source solution HangFire provides a common programming model for background job processing for ASP.NET. Our reviewer says it's worth checking out.

microsoft-net-framework-4-5.jpg

A common programming chore is a long-running task such as processing files, data cleanup, and so forth. Programming a solution in .NET is not always straightforward.

In the past, I've used Windows services quite a bit to handle repeated tasks that are scheduled; the Windows Task Scheduler is another option. However, HangFire provides a less complex solution that utilizes the ASP.NET request processing pipeline -- it is similar to the resque Ruby library. HangFire provides a common programming model for background job processing. Let's take a closer look at what if offers and how it is used.

Setting up your environment

HangFire is completely open source, so you are welcome to contribute to its development via its GitHub project. You can install HangFire via NuGet as well as MyGet.

Figure A shows the HangFire package located via the NuGet Package Manager in Visual Studio 2012. In addition, you can use the Package Manager Console as shown in Figure B. Notice the output in Figure B shows that choosing the base HangFire package in Figure A results in the dependent packages (like HangFire.Web) being installed as well.

Figure A

hangfirefiga053014.jpg

Finding and installing HangFire via the NuGet Package Manager.

Figure B

hangfirefigb053014.jpg

Installing HangFire via the Package Manager Console in Visual Studio 2012.

The default installation includes SQL Server support. An additional package (HangFire.Redis) must be installed to utilize Redis for storage -- Figure C shows its installation. As a result of the installation, the necessary DLL files appear in the Visual Studio project references list as shown in Figure D.

Figure C

hangfirefigc053014.jpg

Installing the additional packages for using Redis.

Figure D

hangfirefigd053014.jpg

The base installed HangFire DLL files shown in Va isual Studio project.

It is interesting to see what other NuGet packages are used. For HangFire, the object-relational mapper (ORM) Dapper is used along with Common.Logging. Another tool used is WebActivatorEx, which allows other packages to execute startup code in a web application. It uses the Json.NET JSON framework for .NET (Newtonsoft.Json). Your project's package.config will also contain the following references.

<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Common.Logging" version="2.1.2" targetFramework="net45" />
<package id="Dapper" version="1.13" targetFramework="net45" />
<package id="HangFire" version="0.8.3" targetFramework="net45" />
<package id="HangFire.Core" version="0.8.3" targetFramework="net45" />
<package id="HangFire.SqlServer" version="0.8.3" targetFramework="net45" />
<package id="HangFire.Web" version="0.8.3" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" />
<package id="WebActivatorEx" version="2.0.5" targetFramework="net45" />
</packages>

Another addition to your project is the HangFireConfig.cs file added to the App_Start folder as shown in Figure E; this is where the server used by HangFire is started and the backend data store connection is set up. A key HangFire feature is its immunity to web server threads being terminated as the necessary data is stored -- by default, it uses SQL Server for this data persistence, but other options are available as will be discussed. To follow the default setup, one of the first things to do post installation is configure your SQL Server connection.

Figure E

hangfirefige053014.jpg

The HangFireConfig.cs file is added during HangFire installation.

The following listing shows the complete code of the default HangFireConfig.cs file. It uses the WebActivatorEx package for starting and stopping the server. The HangFire server is declared as an instance of AspNetBackgroundJobServer. The storage is instantiated using SqlServerStorage and passing in the SQL Server connection string. You need to create a database for HangFire -- I created an empty database called HangFire, but you can use any name. With the database created, you need to set up the SQL Server connection string for it. In the code listing, I am using a SQL Server Express instance with the previously mentioned database along with a trusted connection. If you ever forget the syntax for connection strings, the ConnectionStrings.com site is a great reference. The final step in the code is starting the server.

using HangFire;
using HangFire.SqlServer;
using HangFire.Web;
[assembly: WebActivatorEx.PostApplicationStartMethod(  typeof(TechRepublicHangFire.HangFireConfig), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(
    typeof(TechRepublicHangFire.HangFireConfig), "Stop")]
namespace TechRepublicHangFire {
public class HangFireConfig {
private static AspNetBackgroundJobServer _server;
public static void Start() {
JobStorage.Current = new SqlServerStorage(@"Server=./sqlexpress; Database=HangFire; Trusted_Connection=True;");
_server = new AspNetBackgroundJobServer();
_server.Start();
}
public static void Stop()  {
_server.Stop();
}  }   }

With our connection string set up, we can build the project and run it to make sure everything works. The HangFire monitoring page is accessed via the hangfire.axd service as shown in Figure F. The page provides statistics on jobs, queues, and so on. There is no data to display for our current setup. On the backend, HangFire automatically creates all necessary database objects when first used. Figure G shows the tables created in our once empty database container; these tables are used to track all facets of HangFire tasks -- if the web server goes down, all data is here to pick up right where it left off.

Figure F

hangfirefigf053014.jpg

The basic monitoring page offered by HangFire.

Figure G

hangfirefigg053014.jpg

The database objects created automatically by HangFire.

The BackgroundJob class is used to execute or schedule tasks to run. The method, along with its arguments and state, are passed to the methods, so you code what is needed in an included method or call a method in another class (whatever works for you). The two basic ways to execute code is via the Enqueue and Schedule methods of the BackgroundJob class. You pass the code to be called or executed to these methods, and HangFire takes care of the rest. The HangFire documentation includes two basic examples of sending output to the console, but it gives a general idea of how HangFire works, and it allows you to see what happens in the backend database. The Enqueue method executes the code now.

BackgroundJob.Enqueue(() => System.Console.WriteLine(“TechRepublic.com rules!”));

The Schedule method allows you to execute code sometime in the future as it accepts a second parameter signaling when it should run.

BackgroundJob.Schedule(() => System.Console.WriteLine(“Seriously, TechRepublic.com rules!”), System.TimeSpan.FromMinutes(1));

When you start your application, the first line (Enqueue) will immediately execute, while the scheduled task will execute later. Figure H shows you what happened in the backend database as entries were created in the Job table for each task.

Figure H

hangfirefigh053014.jpg

The Job table is populated with the tasks created in our code.

Redis is another HangFire storage option. It is configured using the previously covered JobStorage class, but the RedisStorage class is used instead of SqlServerStorage in our examples.

JobStorage.Current = new RedisStorage(“redis URL”);

In addition, SQL Azure and MSMQ are mentioned on the HangFire site, but I did not find any concrete examples of usage, although I am sure you can use SQL Azure backend just like normal SQL Server via the correct connection string.

Filling a need

HangFire fills a much needed gap within .NET development, as there are always long-running tasks or jobs that need to be executed. It is a much easier option than creating Windows services, and the simple setup and configuration means it can run within a hosted environment.

There are other options available such as Quartz.NET and, for those using Azure, the WebJobs feature, which (like everything Azure related) seems a bit too involved upon review. My initial reaction with HangFire is positive, as I see actual real-world uses; plus, it is open source and relatively easy to get up and running.

I have only scratched the surface of HangFire usage in this article, but you can peruse their site to get more information -- the discussion area in particular is a great resource. Give HangFire a test drive, and let me know what you think or by all means suggest better alternatives.

About

Tony Patton has worn many hats over his 15+ years in the IT industry while witnessing many technologies come and go. He currently focuses on .NET and Web Development while trying to grasp the many facets of supporting such technologies in a productio...

1 comments