Worker Service

Введение в Worker-сервисы

Последнее обновление: 26.11.2023

Кроме консольных и графических приложений на C# мы можем разрабатывать сервисы - некоторые приложения, которые работают в виде фонового процесса и выполняют некоторую работу. Такие сервисы могут использоваться, например, в фоновой обработке задач по очереди или через промежутки времени. Примером таких сервисов можно назвать, например, службы Windows. Рассмотрим, как мы можем создавать простейшие сервисы.

Для создания сервисов Visual Studio и .NET CLI предоставляют специальные шаблоны. В Visual Studio это шаблон Worker Service:

Создание проекта Worker Service для приложения на C# в Visual Studio

.NET CLI для создания сервисов предоставляет шаблон worker

dotnet new worker

Создадим проект данного типа. Пусть он будет называться WorkerServiceApp. По умолчанию созданный проект будет выглядеть следующим образом:

Проект Worker Service на C# в .NET

Рассмотрим его базовую структуру:

  • Папка Properties содержит файл launchSettings.json, который определяет параметры запуска проекта

  • Файл appsettings.json определяет конфигурацию приложения

  • Файл appsettings.Development.json определяет конфигурацию приложения для стадии разработки

  • Файл Program.cs содержит определение класса Program (по умолчанию без явного определения этого класса), который является точкой входа в программу

  • Файл Worker.cs определяет собственно класс сервиса, который по умолчанию называется Worker

  • Файл workerserviceapp.cproj - стандартный файл с расширением csproj, который определяет конфигурацию проекта

Конфигурация проекта

Откроем файл конфигурации проекта с расширением csproj он выглядит примерно следующим образом:

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UserSecretsId>dotnet-WorkerServiceApp-21388fcc-d283-4fc4-ab25-5dfa3ffcbfb3</UserSecretsId>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
  </ItemGroup>
</Project>

Здесь мы видим, что и в качестве фреймворка проекта используется подсистема Microsoft.NET.Sdk.Worker, которая предназначена специально для создания сервисов.

Также в отличие от стандартного проекта консольного приложения здесь мы видим, что в проект добавлен по умолчанию Nuget-пакет "Microsoft.Extensions.Hosting", функциональность которого позволяет развертывать и запускать сервисы.

И также среди настроек имеет элемент <UserSecretsId> который представляет секретный код для текущего проекта, который генерируется на основе значения Guid.

Рассмотрим ключевые компоненты программы - класс сервиса Worker и запускающий его хост.

Сервис Worker

Сервис должен представлять объект IHostedService. Класс Worker наследуется от BackgroundService, который является реализацией IHostedService:

namespace WorkerServiceApp
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

Через конструктор класс Worker получает объект ILogger для выполнения логгирования (ILogger по умолчанию передается в приложение через систему внедрения зависимостей). А в методе ExecuteAsync() применяется бесконечный цикл (пока не будет установлен токен отмены), в котором раз в секунду с помощью ILogger выполняется некоторая запись в лог. По умолчанию логгирование идет на консоль.

Запуск сервиса

Рассмотрим, как происходит запуск и выполнение сервиса Worker. Как и в других проектах на C# выполнение начинаяется с кода файла Program.cs, который неявно определяет класс Program:

using WorkerServiceApp;   // пространство имен класса Worker

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
    })
    .Build();

host.Run();

Сервис развертывается и запускается в рамках некоторого хоста - объекта IHost. Для создания объекта IHost применяется объект IHostBuilder. А чтобы создать IHostBuilder, применяется метод Host.CreateDefaultBuilder().

IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args);

Далее нам надо добавить наш сервис Worker. И для этого у IHostBuilder вызывается метод ConfigureServices(). В ConfigureServices передается делегат Action<IServiceCollection>, который регистрирует сервисы. Он принимает параметр типа IServiceCollection - коллекция сервисов, в которую необходимо добавить наш сервис.

Для добавления (или можно сказать регистрации) сервиса у коллекции сервисов вызывается метод AddHostedService():

hostBuilder = hostBuilder.ConfigureServices(services => services.AddHostedService<Worker>());

Метод AddHostedService() типизируется типом IHostedService - то есть по сути типом сервиса, который должен предоставлять реализацию интерфейса IHostedService. По умолчанию это автосгенерированный сервис Worker. Стоит отметить, что сервис добавляет как синглтон.

И в конце необходимо построить объект Host с помощью метода Build():

IHost host = hostBuilder.Build();

После создания хоста запускаем его методом Run(), вместе с этим запускаются и все сервисы хоста.

host.Run();

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

Фоновый сервис Worker в приложении на C# и .NET

Консоль сервиса сначала отображает некоторую базовую информацию и затем собственно идет вывод сообщений логгера.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850