Веб-приложения - это не только, обработка HTTP-запросов. Часто приложению приходится выполнять какую-то работу в фоне - например, списывать деньги со счета по расписанию или выполнять отправку email-сообщения, не задерживая при этом ответ пользователю.
Решают эту задачу все по-разному - кто-то создает свою службу Windows, кто-то запускает код по расписанию с помощью планировщика Windows. Есть ещё один прекрасный способ - библиотека Hangfire.
В основе идеи Hangfire лежит ключевое "fire-and-forget", что означает запустить код на выполнение и забыть - далее он выполнится в фоне без вашего участия. При этом вам не потребуются дополнительные инфраструктурные вмешательства (такие как Windows Service), что существенно упростит процесс развертывания. Hangfire подключается к приложению путем установки пакета из Nuget.
Подключение Hangfire к приложению
Для подключения Hangfire к приложению нужно установить пакет Hangfire из Nuget:
Install-Package HangFire
Данный пакет содержит базовую инфраструктуру Hangfire и хранилище для SQL Server. Hangfire использует внешнее хранилище данных для очередей для того, чтобы фоновые задачи не удалялись при перезапуске приложения. По умолчанию в качестве хранилища используется SQL Server, в платной Pro-версии есть возможность работать с Redis. Также я сделал свой провайдер для Mongo.
Для запуска Hangfire используется инфраструктура OWIN (отличное решение, с учетом задела на будущее), для конфигурации нужно выполнить метод UseHangfire
:
public void Configuration(IAppBuilder app)
{
app.UseHangfire(config =>
{
config.UseSqlServerStorage("<connection string or its name>");
config.UseServer();
});
}
Метод UseHangfire
принимает в качестве аргумента метод для конфигурирования Hangfire. Здесь нужно обязательно использовать какой-либо из типов источников данных. Провайдер для SQL Server автоматически создаст нужные таблице в вашей базе данных, поэтому дополнительных действий тут не требуется - нужно только указать строку подключения SQL Server:
public void Configuration(IAppBuilder app)
{
app.UseHangfire(config =>
{
config.UseSqlServerStorage(
@"Data Source=.\SQLEXPRESS;Initial Catalog=TestApplication;Integrated Security=True");
config.UseServer();
});
}
Необходимые таблицы будут созданы при первом запуске приложения:

Аналогично работают провайдеры для Redis и Mongo — нужные коллекции создаются автоматически.
Этого достаточно для того, чтобы Hangfire заработал. Можно запустить приложение и вам будет доступен Dashboard от Hangifre по адресу /hangfire
. Там содержаться все задачи — выполненные, запланированные, ошибочные и т.д.

Если требуется закрыть паролем этот Dashboard, то существует отдельный пакет - Hangfire.Dashboard.Authorization
, который поддерживает встроенную аутентификацию ASP.NET, а также Basic Authentication. Не забывайте настроить HTTPS для вашего веб-приложения.
Такой конфигурации достаточно, чтобы потестировать Hangfire, но для продакшн-среды нужны некоторые дополнительные действия. Что именно нужно сделать зависит от типа хостинга вашего приложения, но в целом идея заключается в том, чтобы убедиться, что ASP.NET приложение не переходит в спящий режим. Подробнее это описано в официальной документации.
Запуск задач при помощи Hangfire
Hangfire имеет возможность запуска разных типов задач:
- простая задача в фоне, которая запустится как можно скорее ("fire-and-forget")
- задача, выполняемая с задержкой (например, через 1.5 часа после постановки в очередь)
- задача, выполняемая периодически по заданному расписанию
При запуске задачи в Hangfire она помещается в очередь (в хранилище появляется соответствующая запись) и далее выполняется в фоне.
Для примера, создадим приложение, отправляющее email-ы. Почему это нужно делать в фоне? Дело в том, что скорость отправки сообщения зависит от конкретного SMTP-сервера. Эта задержка увеличивается, если отправлять несколько сообщений. Например, у меня были случаи, когда по запросу от пользователя нужно было рассылать более 10 сообщений - в этом случае задержка становится ощутимой. В случае с Hangfire мы просто ставим задачи по отправке email-сообщений в очередь и больше не задерживаем пользователя. Поэтому предпочтительнее обрабатывать такие задачи именно в фоне.
Создадим простейший сервис для отправки сообщения:
public static class EmailService
{
public static void Send(string from, string to, string subject, string body)
{
using (var smtp = new SmtpClient())
{
// ...
smtp.Send(from, to, subject, body);
}
}
}
Чтобы поставить задачу на отправку сообщения в очередь следует воспользоваться объектом BackgroundJob
:
public ActionResult Send()
{
BackgroundJob.Enqueue(() =>
EmailService.Send("from@email.com", "to@email.com", "Subject", "Text"));
return View();
}
Как только задачи будут поставлены в очередь, это будет видно в Hangfire Dashboard:

Здесь же можно отслеживать успешные и неудачные попытки выполнения заданий, отслеживать задания по расписанию и визульно видеть объем задач, выполняемых в фоне.