0Pricing
C# Academy · Урок

Проекты рабочих служб

Создавайте автономную рабочую службу, настраивайте DI и ведение журналов и развёртывайте её как службу Windows или демон Linux.

«Проекты рабочих служб» — бесплатный урок C# Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Что такое рабочая служба

Рабочая служба — это шаблон проекта .NET для создания долгоживущих фоновых приложений: без веб-сервера и конечных точек HTTP. Это лёгкий хост, идеально подходящий для обработчиков очередей, запланированных задач и служб в стиле демонов.

Создание рабочей службы

Используйте шаблон CLI, чтобы создать структуру проекта рабочей службы. Он генерирует минимальный файл Program.cs и класс Worker.cs, наследующийся от BackgroundService.

# Create a new Worker Service project
dotnet new worker -n OrderProcessor

# Generated structure:
# OrderProcessor/
#   Program.cs       — host configuration
#   Worker.cs        — your BackgroundService subclass
#   appsettings.json

Program.cs рабочей службы

Сгенерированный файл Program.cs использует универсальный хост. Вы настраиваете DI, журналирование и конфигурацию, а также регистрируете рабочую службу — так же, как в ASP.NET Core, но без веб-сервера.

using Microsoft.Extensions.Hosting;

var builder = Host.CreateApplicationBuilder(args);

// Register services
builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddHostedService<OrderProcessorWorker>();

var host = builder.Build();
host.Run();

Класс рабочей службы

Наследуйтесь от BackgroundService и реализуйте ExecuteAsync. Хост вызывает этот метод при запуске и передаёт токен отмены, который активируется при завершении работы.

public class OrderProcessorWorker : BackgroundService
{
    private readonly IServiceScopeFactory _factory;
    private readonly ILogger<OrderProcessorWorker> _logger;

    public OrderProcessorWorker(
        IServiceScopeFactory factory,
        ILogger<OrderProcessorWorker> logger)
    {
        _factory = factory;
        _logger  = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        while (!ct.IsCancellationRequested)
        {
            using var scope = _factory.CreateScope();
            var repo = scope.ServiceProvider.GetRequiredService<IOrderRepository>();
            var pending = await repo.GetPendingAsync(ct);
            foreach (var order in pending)
                await ProcessOrderAsync(order, ct);
            await Task.Delay(TimeSpan.FromSeconds(10), ct);
        }
    }

    private Task ProcessOrderAsync(Order o, CancellationToken ct) =>
        Task.Delay(100, ct); // placeholder
}

Конфигурация и DI в рабочих службах

Рабочие службы поддерживают всю систему конфигурации .NET: параметры appsettings, переменные среды и секреты пользователя. Внедряйте IConfiguration или строго типизированные параметры.

builder.Services.Configure<WorkerSettings>(
    builder.Configuration.GetSection("Worker"));

public class OrderProcessorWorker : BackgroundService
{
    private readonly WorkerSettings _settings;

    public OrderProcessorWorker(IOptions<WorkerSettings> opts, ...)
        => _settings = opts.Value;

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        while (!ct.IsCancellationRequested)
        {
            // ...
            await Task.Delay(_settings.PollIntervalSeconds * 1000, ct);
        }
    }
}

Журналирование в рабочих службах

Универсальный хост автоматически настраивает журналирование. Используйте ILogger<T> для структурированного журналирования. В рабочей среде настройте Serilog, Application Insights или другой поставщик.

// Add Serilog to a Worker Service
builder.Host.UseSerilog((ctx, logConfig) =>
    logConfig
        .ReadFrom.Configuration(ctx.Configuration)
        .WriteTo.Console()
        .WriteTo.Seq(ctx.Configuration["Seq:ServerUrl"]!));

// Structured logging in the worker:
_logger.LogInformation("Processing {Count} orders at {Time}",
    orders.Count, DateTimeOffset.UtcNow);
_logger.LogError(ex, "Failed to process order {OrderId}", order.Id);

Запуск в качестве службы Windows

Используйте UseWindowsService(), чтобы запустить рабочую службу как службу Windows. Служба запускается и останавливается вместе с ОС и продолжает работу после выхода пользователей из системы.

// dotnet add package Microsoft.Extensions.Hosting.WindowsServices

builder.Services.AddWindowsService(options =>
    options.ServiceName = "OrderProcessor");

// Build and publish:
// dotnet publish -c Release -o ./publish

// Install as Windows Service:
// sc create OrderProcessor binpath="C:\services\publish\OrderProcessor.exe"
// sc start OrderProcessor

Запуск в качестве демона Linux Systemd

Используйте UseSystemd() для интеграции с systemd в Linux. Служба получает корректные сигналы остановки и интегрируется с журналированием journald.

// dotnet add package Microsoft.Extensions.Hosting.Systemd

builder.Services.AddSystemd();

// Systemd unit file: /etc/systemd/system/orderprocessor.service
// [Unit]
// Description=Order Processor Worker
// [Service]
// Type=notify
// ExecStart=/usr/bin/dotnet /app/OrderProcessor.dll
// Restart=always
// [Install]
// WantedBy=multi-user.target

// Commands:
// sudo systemctl enable orderprocessor
// sudo systemctl start orderprocessor
// sudo journalctl -u orderprocessor -f

Запуск в Docker

Рабочие службы идеально подходят для контейнеров Docker: сопоставление портов не требуется, достаточно запускать процесс в цикле до остановки контейнера.

# Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app

FROM mcr.microsoft.com/dotnet/runtime:9.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "OrderProcessor.dll"]

# docker-compose.yml:
# services:
#   worker:
#     build: .
#     environment:
#       - ConnectionStrings__Default=Server=db;...
#     depends_on: [db]

Практический пример: обработчик почтовых сводок

Полноценная рабочая служба, которая ежедневно отправляет сводки по электронной почте, читая данные из базы данных и передавая их службе электронной почты.

public class EmailDigestWorker : BackgroundService
{
    private readonly IServiceScopeFactory _factory;
    private readonly ILogger<EmailDigestWorker> _log;

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        // Run daily at midnight UTC
        while (!ct.IsCancellationRequested)
        {
            var now = DateTime.UtcNow;
            var next = now.Date.AddDays(1); // next midnight
            await Task.Delay(next - now, ct);

            using var scope = _factory.CreateScope();
            var mailer = scope.ServiceProvider.GetRequiredService<IDigestMailer>();

            try   { await mailer.SendDailyDigestsAsync(ct); }
            catch (Exception ex) { _log.LogError(ex, "Digest failed"); }
        }
    }
}

Быстрая проверка

В чём заключается основное различие между проектом рабочей службы и проектом ASP.NET Core Web API?

Итоги: проекты рабочих служб

Главные выводы:

  • Рабочая служба = универсальный хост + BackgroundService, без веб-сервера
  • Полная поддержка DI, журналирования и конфигурации — но без HTTP
  • UseWindowsService() для развёртывания в качестве службы Windows
  • UseSystemd() для демона Linux с интеграцией journald
  • Разворачивайте рабочие службы в контейнерах Docker для облачной фоновой обработки
  • Всегда используйте IServiceScopeFactory для зависимостей с ограниченным временем жизни в рабочей службе

Часто задаваемые вопросы

Урок «Проекты рабочих служб» бесплатный?

Да — полный текст урока «Проекты рабочих служб» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Проекты рабочих служб»?

Создавайте автономную рабочую службу, настраивайте DI и ведение журналов и развёртывайте её как службу Windows или демон Linux. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Проекты рабочих служб»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. IHostedService и BackgroundService
  2. Проекты рабочих служб
  3. Периодические задачи и таймеры
  4. Плановые задания Quartz.NET
← Назад к C# Academy