BackgroundService, Net, AspNet
260213_BackgroundServices_In_Net_And_AspNet_.docx
26.02.13 Alice
В AspNetCore -
есть сущности BAckGroundServices, DI, и различные регистрации классов. Внимание
вопрос. В .Net существуют ли такие сущности, чтобы как-то начать проект C#. ?
Да, в .NET существует целый набор сущностей и
механизмов, позволяющих начать и структурировать проект на C#. Разберём
ключевые из них.
Основные строительные блоки проекта C# в .NET
1. Проектные шаблоны (Project Templates)
При создании нового проекта в Visual Studio или через dotnet CLI вы выбираете
шаблон, который задаёт базовую структуру:
- Console
App — простейший проект для командной
строки;
- Web API — для
создания REST-сервисов;
- ASP.NET
Core Web App — полноценное веб‑приложение;
- Class
Library — библиотека классов;
- Worker
Service — фоновые сервисы.
Пример через CLI:
bash
dotnet new console
-n MyApp
dotnet new webapi
-n MyApi
2. Program.cs / Startup.cs (в зависимости от версии)
Это «точка входа» приложения:
- В .NET
6+ — упрощённый Program.cs с минимальной конфигурацией:
csharp
var builder = Host.CreateApplicationBuilder(args);
var app = builder.Build();
app.Run();
- В .NET 5 и ниже — классический Startup.cs с методами ConfigureServices и Configure.
3. Dependency Injection (DI) Container
Встроенное средство управления зависимостями:
- Регистрация
сервисов в Program.cs/Startup.cs:
csharp
builder.Services.AddScoped<IMyService,
MyService>();
builder.Services.AddSingleton<IConfig,
Config>();
- Внедрение
через конструктор:
csharp
public class
MyController {
private readonly IMyService _service;
public
MyController(IMyService service) => _service = service;
}
4.
Background Services
Для фоновых задач есть базовый класс BackgroundService:
csharp
public class MyBackgroundService : BackgroundService {
protected
override async Task ExecuteAsync(CancellationToken stoppingToken) {
while
(!stoppingToken.IsCancellationRequested) {
// Ваша логика
await Task.Delay(1000, stoppingToken);
}
}
}
Регистрация:
csharp
builder.Services.AddHostedService<MyBackgroundService>();
5. Конфигурация (Configuration)
Загрузка настроек из разных источников:
csharp
var builder = Host.CreateApplicationBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json");
builder.Configuration.AddEnvironmentVariables();
Доступ к настройкам:
csharp
var myValue =
builder.Configuration["MyKey"];
6. Логирование (Logging)
Встроенное логирование через ILogger:
csharp
public class MyService {
private
readonly ILogger<MyService> _logger;
public
MyService(ILogger<MyService> logger) => _logger = logger;
public void
DoWork() {
_logger.LogInformation("Работа выполнена");
}
}
7. Middleware (для веб‑приложений)
Компоненты конвейера обработки HTTP‑запросов:
csharp
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
8. Сервисы ASP.NET Core (если нужно веб)
- AddControllers() — для
API;
- AddRazorPages() — для
Razor Pages;
- AddMvc() — для
классического MVC.
Как начать проект: пошаговый алгоритм
- Создайте
проект:
bash
dotnet new webapi
-n MyProject
- Определите
интерфейсы и классы в папке Services/.
- Зарегистрируйте
сервисы в Program.cs:
csharp
builder.Services.AddScoped<IUserService,
UserService>();
- Добавьте
фоновые задачи (если нужно):
csharp
builder.Services.AddHostedService<DataProcessorService>();
- Настройте
конфигурацию через appsettings.json.
- Запустите:
bash
dotnet run
Ключевые пространства имён
- Microsoft.Extensions.DependencyInjection — DI;
- Microsoft.Extensions.Hosting — хостинг
и фоновые сервисы;
- Microsoft.Extensions.Configuration — конфигурация;
- Microsoft.Extensions.Logging — логирование.
Таким образом, .NET предоставляет полный набор
инструментов для старта проекта — от базовой структуры до продвинутых
механизмов вроде DI и фоновых сервисов.
Напиши простой пример с Worker Service для
.NetCore
Ниже — полный рабочий пример фонового
сервиса (Worker
Service) в .NET 6+ с пояснениями.
1. Создание проекта
Откройте терминал и выполните:
bash
dotnet new worker -n SimpleWorkerDemo
cd SimpleWorkerDemo
Это создаст проект с базовой структурой:
- Worker.cs — класс
фоновой службы;
- Program.cs — точка
входа и конфигурация.
2. Модифицируем Worker.cs
Замените содержимое файла Worker.cs на следующий
код:
csharp
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class Worker : BackgroundService
{
private
readonly ILogger<Worker> _logger;
public
Worker(ILogger<Worker> logger)
{
_logger
= logger;
}
protected
override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Worker running. Press Ctrl+C to
stop.");
while
(!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker is doing work...");
// Здесь ваша бизнес-логика
await Task.Delay(5000, stoppingToken); // Ждать 5 секунд
}
_logger.LogInformation("Worker is stopping.");
}
}
Что делает код:
- Принимает ILogger через DI.
- В методе ExecuteAsync
выполняется цикл, пока не запрошен останов.
- Каждые
5 секунд пишет лог.
- Корректно реагирует
на сигнал остановки (Ctrl+C).
3. Настройка Program.cs (по умолчанию уже готово)
Стандартный Program.cs в .NET 6+ уже содержит всё необходимое:
csharp
using IHost host =
Host.CreateApplicationBuilder(args).Build();
host.Run();
Он автоматически:
- настраивает
логирование;
- регистрирует
Worker как фоновый сервис;
- запускает
хост.
4. Добавление конфигурации (опционально)
Если нужно читать настройки из appsettings.json:
- Создайте
файл appsettings.json в корне проекта:
json
{
"WorkerSettings":
{
"IntervalSeconds": 10,
"Message": "Hello from config!"
}
}
- Добавьте
класс для настроек:
csharp
public class
WorkerSettings
{
public int
IntervalSeconds { get; set; }
public
string Message { get; set; }
}
- Внедрите
настройки в Worker:
csharp
public class Worker
: BackgroundService
{
private
readonly ILogger<Worker> _logger;
private
readonly WorkerSettings _settings;
public
Worker(ILogger<Worker> logger, IOptions<WorkerSettings> settings)
{
_logger = logger;
_settings = settings.Value;
}
protected
override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Worker running. Interval:
{Interval}s", _settings.IntervalSeconds);
while
(!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Message: {Message}",
_settings.Message);
await Task.Delay(_settings.IntervalSeconds * 1000, stoppingToken);
}
}
}
- Зарегистрируйте
настройки в Program.cs:
csharp
var builder = Host.CreateApplicationBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json");
builder.Services.Configure<WorkerSettings>(
builder.Configuration.GetSection("WorkerSettings"));
builder.Services.AddHostedService<Worker>();
IHost host = builder.Build();
host.Run();
5. Запуск и тестирование
- Соберите
проект:
bash
dotnet build
- Запустите:
bash
dotnet run
Ожидаемый вывод в консоли:
info:
SimpleWorkerDemo.Worker[0]
Worker running. Interval: 10s
info:
SimpleWorkerDemo.Worker[0]
Message: Hello from config!
info:
SimpleWorkerDemo.Worker[0]
Message: Hello from config!
...
- Остановить
сервис: нажмите Ctrl+C.
6. Публикация (опционально)
Чтобы собрать самодостаточный исполняемый файл:
bash
dotnet publish -c Release -r win-x64 --self-contained
true
Результат будет в папке ./bin/Release/net8.0/win-x64/publish/.
Ключевые моменты
- BackgroundService — базовый
класс для фоновых задач.
- ExecuteAsync — метод,
где выполняется основная логика.
- CancellationToken —
позволяет корректно завершать работу.
- DI — все
зависимости (логгер, настройки) внедряются через конструктор.
- Логирование —
доступно по умолчанию через ILogger.
Этот пример можно расширять: добавлять работу с БД,
HTTP‑запросы, обработку очередей и т. д.
ВЫ используете сущности из Asp Net Core - в
часности BAckgroundService.cs, а не из .Net, Или эти сущности есть и в .Net и в
Asp NetCore Я думал, что BAckgroundService - это сущность из Asp NetCore
Вы затронули важный архитектурный момент.
Разберёмся детально.
Где именно находится BackgroundService
Класс BackgroundService не является частью ASP.NET Core в строгом
смысле. Он входит в пакет Microsoft.Extensions.Hosting (пространство
имён Microsoft.Extensions.Hosting), который:
- является частью
.NET (не только ASP.NET Core);
- предназначен
для общего хостинга приложений (любых, не только веб);
- доступен в
.NET 5+, .NET 6+, .NET 8+ и т. д.
Ключевые факты
- Независимость
от веб‑стека
BackgroundService можно использовать в: - консольных
приложениях;
- сервисах
Windows;
- приложениях
IoT;
- любых не‑веб
проектах .NET.
- Где он
определён
Сборка: Microsoft.Extensions.Hosting.Abstractions.dll
Пространство имён: Microsoft.Extensions.Hosting
(не Microsoft.AspNetCore.*!). - Как
подключается
Пакет Microsoft.Extensions.Hosting входит в: - .NET SDK по
умолчанию;
- шаблоны worker и web через
зависимости.
Практическая проверка
Создайте чистое консольное приложение (без
ASP.NET):
bash
dotnet new console -n ConsoleWorker
cd ConsoleWorker
Добавьте зависимость (если её нет):
bash
dotnet add package Microsoft.Extensions.Hosting
Теперь вы можете использовать BackgroundService даже без
ASP.NET:
csharp
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
class MyWorker : BackgroundService
{
protected
override Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine("Работаю в
консольном приложении!");
return Task.CompletedTask;
}
}
// В Program.cs
using var host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services
=> {
services.AddHostedService<MyWorker>();
})
.Build();
await
host.RunAsync();
Почему возникает путаница
- Шаблоны
ASP.NET Core включают Microsoft.Extensions.Hosting
В веб‑проектах этот пакет подтягивается автоматически, поэтому кажется, что BackgroundService — «веб‑фича». - Общая
экосистема .NET
Многие компоненты (DI, конфигурация, логирование) едины для всех типов приложений .NET. BackgroundService — один из них. - Документация
часто показывает примеры в контексте ASP.NET
Из‑за популярности веб‑разработки большинство туториалов используют ASP.NET, но это не значит, что компонент принадлежит только ему.
Вывод
- BackgroundService — часть .NET, а не ASP.NET Core.
- Он
предназначен для любых фоновых задач в приложениях .NET (веб,
консольных, сервисных и др.).
- Его
зависимость — Microsoft.Extensions.Hosting, который
является базовым пакетом .NET, а не веб‑фреймворком.
Таким образом, вы можете смело использовать BackgroundService в любом
проекте .NET, даже если он не имеет отношения к веб‑разработке.
Тогда напишите мне два примера начального
проекта для Worker - AspNetCore - Net ---------- Что можно сразу взять из
коробки для AspNetCore и .Net
Ниже — два готовых к запуску примера
проектов для фоновых сервисов: один на ASP.NET Core (веб‑контекст),
второй на чистом .NET (консольный). Оба используют BackgroundService и работают «из
коробки».
1. Проект на
ASP.NET Core (Web + Background Service)
Сценарий: веб‑приложение, которое параллельно выполняет
фоновые задачи (например, сбор статистики, отправку уведомлений).
Шаг 1. Создание проекта
bash
dotnet new web -n
WebWorkerApp
cd WebWorkerApp
Шаг 2. Добавление фонового сервиса
Создайте файл Services/MyBackgroundWorker.cs:
csharp
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class MyBackgroundWorker : BackgroundService
{
private
readonly ILogger<MyBackgroundWorker> _logger;
public
MyBackgroundWorker(ILogger<MyBackgroundWorker> logger)
{
_logger
= logger;
}
protected
override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("MyBackgroundWorker
запущен.");
while
(!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Выполняю фоновую задачу...");
await Task.Delay(10000, stoppingToken); // Каждые 10 сек
}
_logger.LogInformation("MyBackgroundWorker остановлен.");
}
}
Шаг 3. Регистрация в
DI
В Program.cs добавьте:
csharp
var builder = WebApplication.CreateBuilder(args);
// Добавляем фоновый сервис
builder.Services.AddHostedService<MyBackgroundWorker>();
var app = builder.Build();
app.MapGet("/", () => "Hello from
ASP.NET Core!");
app.Run();
Шаг 4. Запуск
bash
dotnet run
Что увидите:
- Веб‑сервер
стартует на http://localhost:5000.
- В логах
каждые 10 сек будет появляться:
Выполняю фоновую задачу... - Откройте в
браузере http://localhost:5000 — увидите
ответ веб‑приложения.
2. Проект на чистом .NET (Console Worker)
Сценарий: автономное консольное приложение, выполняющее
фоновые задачи (например, мониторинг файлов, отправка данных в облако).
Шаг 1. Создание проекта
bash
dotnet new worker -n ConsoleWorkerApp
cd ConsoleWorkerApp
Шаблон worker создаёт готовый проект с BackgroundService.
Шаг 2. Модификация Worker.cs
Замените содержимое Worker.cs на:
csharp
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class Worker : BackgroundService
{
private
readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker>
logger)
{
_logger
= logger;
}
protected
override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Worker запущен. Нажмите Ctrl+C для остановки.");
while
(!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Фоновая задача
выполняется...");
await Task.Delay(5000, stoppingToken); // Каждые 5 сек
}
_logger.LogInformation("Worker остановлен.");
}
}
Шаг 3. Проверка
Program.cs
Убедитесь, что Program.cs выглядит так (стандартный шаблон):
csharp
using IHost host =
Host.CreateApplicationBuilder(args).Build();
host.Run();
Шаг 4. Запуск
bash
dotnet run
Что увидите:
- В консоли
каждые 5 сек:
Фоновая задача выполняется... - Для
остановки нажмите Ctrl+C.
Что «из коробки» доступно в каждом случае
Для
ASP.NET Core (web шаблон)
- Веб‑сервер (Kestrel)
и маршрутизация.
- DI‑контейнер с
автоматической регистрацией сервисов.
- Логирование (в
консоль, debug, Event Log).
- Конфигурация (appsettings.json,
переменные окружения).
- Middleware для
обработки HTTP‑запросов.
- Hosted
Services (включая BackgroundService).
Для чистого .NET (worker шаблон)
- Хостинг (IHost, Host.CreateApplicationBuilder).
- DI‑контейнер и регистрация
HostedService.
- Логирование (по
умолчанию в консоль).
- Конфигурация (можно
подключить appsettings.json).
- Обработка
сигналов ОС (Ctrl+C для корректного завершения).
- Жизненный
цикл приложения (старт/стоп сервисов).
Как добавить конфигурацию (опционально)
Если нужно читать настройки из appsettings.json в любом из
проектов:
- Создайте
файл appsettings.json:
json
{
"PollInterval": 7000
}
- Добавьте
класс настроек:
csharp
public class
AppSettings
{
public int
PollInterval { get; set; }
}
- В Program.cs (для
обоих проектов):
csharp
var builder = Host.CreateApplicationBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json");
builder.Services.Configure<AppSettings>(
builder.Configuration);
builder.Services.AddHostedService<Worker>(); // или MyBackgroundWorker
IHost host = builder.Build();
host.Run();
- В сервисе
используйте настройки:
csharp
public Worker(ILogger<Worker> logger,
IOptions<AppSettings> settings)
{
_logger =
logger;
_interval = settings.Value.PollInterval;
}
Итог
- ASP.NET Core →
подходит, если нужен веб‑интерфейс + фоновые задачи.
- Чистый
.NET (worker) → идеален
для автономных фоновых приложений без веб‑части.
- Оба
используют один и тот же механизм BackgroundService из Microsoft.Extensions.Hosting.
- Шаблоны из
CLI (dotnet new) дают рабочую основу — достаточно
добавить свою логику в ExecuteAsync.
Но я не понял - Все таки есть разница в коде
в контексте использования сущностей и поведения двух Приложений ? В чем разница
?
Да, разница есть — не в сущности BackgroundService (она одинакова
в обоих случаях), а в контексте запуска, окружении и доступных сервисах.
Разберём по пунктам.
1. Точка входа и хост
ASP.NET Core (web шаблон)
- Хост создаётся через WebApplication.CreateBuilder().
- Автоматически
настраивает:
- Kestrel
(веб‑сервер);
- маршрутизацию;
- middleware;
- MVC/API‑конвейер.
- IHost включает
веб‑функциональность.
Чистый .NET (worker шаблон)
- Хост создаётся через Host.CreateApplicationBuilder().
- Нет веб‑сервера
и маршрутизации.
- Минимальное
окружение для фоновых задач.
2. Жизненный цикл приложения
ASP.NET Core
- Приложение
живёт, пока работает веб‑сервер.
- Фоновые
сервисы стартуют после инициализации Kestrel (в .NET 6+).
- Могут обрабатывать
HTTP‑запросы параллельно с фоновыми задачами.
Чистый .NET
- Приложение
живёт, пока работают HostedService.
- Нет
зависимости от веб‑сервера.
- Полный
контроль над временем жизни процесса.
3. Доступ к HTTP‑контексту
ASP.NET Core
- В фоновом
сервисе можно внедрить IHttpContextAccessor (если
включено):
csharp
services.AddHttpContextAccessor();
- Возможен
доступ к текущему HTTP‑запросу (например, для логирования).
Чистый .NET
- IHttpContextAccessor
недоступен (нет HTTP‑контекста).
- Все
операции — вне веб‑запросов.
4. Конфигурация и DI
Одинаково в обоих случаях
- Microsoft.Extensions.DependencyInjection работает идентично.
- Регистрация
сервисов через services.AddHostedService<T>().
- Внедрение
зависимостей (логгер, настройки) — одинаково.
Разница в предустановленных сервисах
- В
ASP.NET Core автоматически добавляются:
- сервисы
MVC/API;
- аутентификация/авторизация;
- CORS,
JSON‑сериализация и т. д.
- В чистом
.NET этих сервисов нет (если не подключать вручную).
5. Логирование и вывод
ASP.NET Core
- Логи по
умолчанию включают:
- HTTP‑запросы
(метод, путь, код ответа);
- время
обработки запроса.
- Можно
настроить фильтрацию логов по категориям (например, скрывать HTTP‑логи для
фоновых задач).
Чистый .NET
- Логи
только от фоновых сервисов и хоста.
- Нет
«лишних» HTTP‑сообщений.
6. Обработка сигналов ОС
Одинаково в обоих случаях
- Оба хоста
реагируют на:
- Ctrl+C
(SIGINT);
- завершение
через kill (SIGTERM).
- Вызывают StopAsync у всех HostedService.
7. Примеры кода: ключевые отличия
ASP.NET Core (Program.cs)
csharp
var builder = WebApplication.CreateBuilder(args);
// Веб‑сервисы + фоновые
builder.Services.AddControllers();
builder.Services.AddHostedService<MyWorker>();
var app = builder.Build();
app.MapControllers();
app.Run(); // Запускает Kestrel и фоновые сервисы
Чистый .NET
(Program.cs)
csharp
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run(); //
Только фоновые сервисы
8. Когда что выбирать?
Используйте ASP.NET Core, если:
- Нужно
обслуживать HTTP‑запросы и выполнять фоновые задачи.
- Требуется
интеграция с веб‑API, аутентификацией, Swagger и т. д.
- Приложение
будет развёрнуто как веб‑сервис (например, в Kubernetes).
Используйте чистый .NET (worker), если:
- Задача — только
фоновая обработка (например, мониторинг файлов, отправка почты).
- Не нужен
веб‑сервер.
- Важно
минимизировать зависимости и размер образа (например, для Docker).
Итог
- BackgroundService — один и
тот же класс в обоих проектах.
- Разница в
окружении:
- ASP.NET Core
добавляет веб‑сервер и HTTP‑контекст;
- чистый
.NET даёт минималистичный хост для фоновых задач.
- Поведение BackgroundService идентично:
- одинаковый
жизненный цикл (StartAsync/StopAsync);
- одинаковая
работа с DI и логированием.
- Выбор
шаблона зависит от сценария:
- веб +
фоновые задачи → ASP.NET Core;
- только
фоновые задачи → чистый .NET.
Тогда напиши мне опять два проекта -- .Net -- AspNetCore
------------------------ Для каждого варианта -- Net и AspNetCore Мы создаем
два BAckgroundServices + SignalRHub Первый BAckgroundServicesA пишет в
BAckgroundServicesB (B - пишет в консоль сообщениеА) и наоборот
BAckgroundServicesB пишет в BAckgroundServicesA (A - пишет в консоль
сообщениеB)
Ниже — два полных проекта (.NET и ASP.NET Core), реализующих:
- два
фоновых сервиса (BackgroundServiceA и BackgroundServiceB), которые
обмениваются сообщениями;
- SignalR Hub для
внешнего наблюдения за обменом (опционально);
- вывод в
консоль для наглядности.
1. Проект на чистом .NET (Console + Worker Services)
Шаг 1. Создание проекта
bash
dotnet new worker -n NetSignalRWorker
cd NetSignalRWorker
Шаг 2. Установка пакетов
bash
dotnet add package Microsoft.AspNetCore.SignalR.Core
dotnet add package Microsoft.Extensions.Hosting
Шаг 3. Создание Hub (для SignalR)
Файл Hubs/ChatHub.cs:
csharp
using Microsoft.AspNetCore.SignalR;
public class ChatHub : Hub
{
public async
Task SendMessage(string user, string message)
{
await
Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Шаг 4. Создание фоновых сервисов
Файл Services/BackgroundServiceA.cs:
csharp
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.SignalR;
public class BackgroundServiceA : BackgroundService
{
private
readonly ILogger<BackgroundServiceA> _logger;
private
readonly IHubContext<ChatHub> _hubContext;
private
readonly BackgroundServiceB _serviceB;
public
BackgroundServiceA(
ILogger<BackgroundServiceA> logger,
IHubContext<ChatHub> hubContext,
BackgroundServiceB serviceB)
{
_logger
= logger;
_hubContext = hubContext;
_serviceB = serviceB;
}
protected
override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while
(!stoppingToken.IsCancellationRequested)
{
var msg = "Сообщение от A к B";
_logger.LogInformation(msg);
// Отправляем в B
_serviceB.ReceiveMessageFromA(msg);
// Отправляем в SignalR
await _hubContext.Clients.All.SendAsync(
"ReceiveMessage", "ServiceA", msg);
await Task.Delay(5000, stoppingToken);
}
}
public void
ReceiveMessageFromB(string message)
{
_logger.LogWarning("A получил от B: {Message}", message);
}
}
Файл Services/BackgroundServiceB.cs:
csharp
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class BackgroundServiceB : BackgroundService
{
private
readonly ILogger<BackgroundServiceB> _logger;
private
readonly BackgroundServiceA _serviceA;
public
BackgroundServiceB(
ILogger<BackgroundServiceB> logger,
BackgroundServiceA serviceA)
{
_logger
= logger;
_serviceA = serviceA;
}
protected
override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while
(!stoppingToken.IsCancellationRequested)
{
var
msg = "Сообщение от B к A";
_logger.LogInformation(msg);
// Отправляем в A
_serviceA.ReceiveMessageFromB(msg);
await Task.Delay(7000, stoppingToken);
}
}
public void
ReceiveMessageFromA(string message)
{
_logger.LogWarning("B получил от A: {Message}", message);
}
}
Шаг 5. Настройка Program.cs
csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.SignalR;
var builder = Host.CreateApplicationBuilder(args);
// Регистрируем Hub
builder.Services.AddSignalR();
// Регистрируем сервисы
(важно: порядок!)
builder.Services.AddSingleton<BackgroundServiceA>();
builder.Services.AddSingleton<BackgroundServiceB>();
builder.Services.AddHostedService<BackgroundServiceA>();
builder.Services.AddHostedService<BackgroundServiceB>();
// Настраиваем SignalR (без веб-сервера — только для отправки)
builder.Services.Configure<HubOptions>(options
=>
{
options.EnableDetailedErrors = true;
});
IHost host = builder.Build();
host.Run();
Шаг 6. Запуск
bash
dotnet run
Что увидите в консоли:
info: BackgroundServiceA[0] Сообщение от A к B
warn:
BackgroundServiceB[0] B получил от A:
Сообщение от A к B
info:
BackgroundServiceB[0] Сообщение от B к
A
warn:
BackgroundServiceA[0] A получил от B:
Сообщение от B к A
SignalR‑клиенты могут подключиться к Hub, но без веб‑сервера
сообщения не будут транслироваться (см. раздел про ASP.NET Core).
2. Проект на
ASP.NET Core (Web + SignalR + Background Services)
Шаг 1. Создание проекта
bash
dotnet new web -n AspNetSignalRWorker
cd AspNetSignalRWorker
Шаг 2. Установка пакетов
bash
dotnet add package Microsoft.AspNetCore.SignalR
Шаг 3. Создание Hub
Файл Hubs/ChatHub.cs (аналогично первому проекту):
csharp
using Microsoft.AspNetCore.SignalR;
public class ChatHub : Hub { }
Шаг 4. Фоновые сервисы (копируем из первого проекта)
Поместите файлы BackgroundServiceA.cs и BackgroundServiceB.cs в папку Services/.
Шаг 5. Настройка Program.cs
csharp
var builder = WebApplication.CreateBuilder(args);
// Добавляем SignalR
builder.Services.AddSignalR();
// Добавляем фоновые сервисы
builder.Services.AddSingleton<BackgroundServiceA>();
builder.Services.AddSingleton<BackgroundServiceB>();
builder.Services.AddHostedService<BackgroundServiceA>();
builder.Services.AddHostedService<BackgroundServiceB>();
var app = builder.Build();
// Маршрутизация SignalR
app.MapHub<ChatHub>("/chatHub");
// Простой эндпоинт для проверки
app.MapGet("/", () => "SignalR
Worker запущен!");
app.Run();
Шаг 6. Создание клиента (HTML + JS)
Создайте файл wwwroot/index.html:
html
<!DOCTYPE html>
<html>
<head>
<title>SignalR Client</title>
</head>
<body>
<h1>Сообщения от сервисов</h1>
<ul id="messages"></ul>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.9/signalr.js"></script>
<script>
const
connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.build();
connection.on("ReceiveMessage",
(user, message) => {
const li = document.createElement("li");
li.textContent = `[${user}]: ${message}`;
document.getElementById("messages").appendChild(li);
});
connection.start()
.catch(err => console.error(err.toString()));
</script>
</body>
</html>
Шаг 7. Запуск
bash
dotnet run
Действия:
- Откройте в
браузере http://localhost:5000 — увидите
страницу с сообщениями.
- В консоли
будут логи обмена между сервисами.
- Сообщения
из BackgroundServiceA/B транслируются в браузер через SignalR.
Ключевые различия между проектами
|
Параметр |
Чистый .NET |
ASP.NET Core |
|
Веб‑сервер |
Нет |
Да (Kestrel) |
|
SignalR‑доступность |
Только внутри
процесса |
Доступно
извне (через /chatHub) |
|
Клиент для
SignalR |
Нужен внешний
(например, JS‑браузер) |
Встроенный
HTML‑клиент |
|
HTTP‑эндпоинты |
Нет |
Да (/ и /chatHub) |
|
Сценарии
использования |
Автономный
фоновый процесс |
Веб‑приложение
+ фоновые задачи |
Как это работает
- Фоновые
сервисы (A и B) запускаются при старте приложения.
- Каждый
сервис:
- отправляет
сообщение соседу (через метод ReceiveMessageFromX);
- выводит
сообщение в консоль;
- транслирует
Почему я задаю такие вопросы. Потому что
часто бывают ситуации когда ты написал проект, создал свои сущности. А потом
оказывается, что такие сущности уже есть из коробки для проектов .Net и ASp
NetCore
Вы задаёте абсолютно правильные
вопросы — и ваша настороженность полностью оправдана. Это один из ключевых
навыков опытного разработчика: не изобретать велосипед, а сначала
выяснить, что уже есть «из коробки».
Разберём, почему так происходит и как этому
противостоять.
Почему мы часто «переизобретаем» решения
- Фрагментарное
обучение
Часто изучаем отдельные технологии (например, «только ASP.NET Core»), не видя всей экосистемы .NET. - Доминирование
веб‑контекста
Большинство туториалов — про веб. Отсюда иллюзия, что BackgroundService — «веб‑фича». - Скрытые зависимости
Многие «стандартные» классы (как BackgroundService) живут в пакетах типа Microsoft.Extensions.*, которые подключаются неявно через шаблоны проектов. - Отсутствие
карты экосистемы
Нет единого справочника: «Вот все встроенные механизмы .NET для фоновых задач, кэширования, конфигурации и т.д.».
Что уже есть «из коробки» в .NET/ASP.NET Core
Базовые механизмы (доступны везде)
- BackgroundService — фоновые
задачи с управлением жизненным циклом.
- IHost/ IHostedService —
универсальный хост для любых приложений.
- DI‑контейнер (Microsoft.Extensions.DependencyInjection) —
встроен по умолчанию.
- Конфигурация (IConfiguration) — чтение
из json/env/args.
- Логирование (ILogger) —
поддержка разных провайдеров.
- Options pattern (IOptions<T>) —
типобезопасная конфигурация.
Веб‑специфичные (ASP.NET Core)
- Middleware —
конвейер обработки HTTP‑запросов.
- Routing/Controllers —
MVC/API.
- Authentication/Authorization — встроенные схемы (JWT, Cookies и др.).
- SignalR — реалтайм‑коммуникации.
- Model
Binding/Validation — автоматическая валидация входных данных.
Для инфраструктурных задач
- Health
Checks — мониторинг состояния сервиса.
- Rate
Limiting — ограничение частоты запросов.
- Output
Caching — кэширование ответов.
- Gzip/Brotli Compression — сжатие ответов.
- CORs/CSP —
безопасность.
Как не «переизобретать»
1. Сначала — документация Microsoft
Перед реализацией любой задачи:
- Зайдите на
.
- Поищите по ключевым словам: «.NET background tasks»,
«ASP.NET Core logging», «.NET configuration».
- Изучите разделы «Guidance» и «How
to».
2. Смотрите на пространства имён
Если ваш код повторяет логику из:
- Microsoft.Extensions.* — скорее
всего, есть встроенное решение.
- System.* —
проверьте, нет ли готового класса.
3. Изучайте шаблоны проектов
Выполните в терминале:
bash
dotnet new --list
Посмотрите, что генерируют шаблоны:
- worker — фоновые
сервисы;
- web — полный
веб‑стек;
- classlib —
библиотеки;
- console —
консольные приложения.
4. Используйте «Dotnet Explorations»
Проекты вроде и — открытые. Можно искать реализации по
ключевым словам.
5. Проверяйте пакеты NuGet
Перед установкой сторонней библиотеки:
- Поищите в
по названию задачи.
- Проверьте,
не входит ли нужное в Microsoft.AspNetCore.App или Microsoft.NET.Sdk.
6. Задавайте «правильные» вопросы
Вместо:
«Как сделать фоновый сервис?»
Спрашивайте:
«Какие встроенные механизмы .NET есть для фоновых
задач?»
Примеры «открытий»
Ситуация 1:
Вы: «Надо написать класс для периодического выполнения задачи».
Решение: BackgroundService + IHostedService.
Ситуация 2:
Вы: «Нужен механизм конфигурации из json‑файла».
Решение: builder.Configuration.AddJsonFile() + IOptions<T>.
Ситуация 3:
Вы: «Как логировать в файл и консоль?»
Решение: встроенные провайдеры ConsoleLogger и FileLogger (через AddFile из Microsoft.Extensions.Logging).
Вывод
Ваш подход — идеальный. Перед реализацией:
- Спросите:
«Есть ли это в .NET/ASP.NET Core из коробки?»
- Проверьте
документацию и исходники.
- Изучите
шаблоны проектов.
- Поищите в
NuGet официальные пакеты Microsoft.
Это сэкономит:
- время (не
писать с нуля);
- ресурсы
(меньше зависимостей);
- нервы
(встроенные решения лучше протестированы).
Правило:
«Если задача типовая (логирование, конфигурация,
фоновые задачи, HTTP‑клиент), скорее всего, в .NET уже есть оптимальное
решение».
Кстати, я видел в этих проектов еще одну
сущность - HostedService Как использовать его ?
IHostedService — фундаментальный интерфейс в .NET для
запуска фоновых задач, интегрированных в жизненный цикл приложения. Разберём, как
и когда его использовать.
Что такое IHostedService
Это интерфейс с двумя методами:
csharp
public interface IHostedService
{
Task
StartAsync(CancellationToken cancellationToken);
Task
StopAsync(CancellationToken cancellationToken);
}
- StartAsync — вызывается
при старте хоста (после инициализации DI, конфигурации и т. д.).
- StopAsync — вызывается
при остановке приложения (например, при получении SIGTERM).
Когда применять
Используйте IHostedService, если нужно:
- Выполнять
задачи в фоне параллельно с основным приложением.
- Гарантированно
очищать ресурсы при завершении работы.
- Интегрироваться
в жизненный цикл хоста .NET (например, ждать готовности БД перед стартом).
- Реализовать
долгоживущие процессы (мониторинг, очереди, таймеры).
Как использовать: пошаговая инструкция
1. Создайте класс, реализующий IHostedService
csharp
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
public class MyHostedService : IHostedService
{
private
Timer _timer;
public Task
StartAsync(CancellationToken cancellationToken)
{
// Инициализация: запускаем таймер,
подключаемся к сервисам и т. д.
_timer = new Timer(
DoWork,
null,
TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return
Task.CompletedTask;
}
private void
DoWork(object state)
{
// Ваша бизнес‑логика (каждые 5 секунд)
Console.WriteLine("Выполняется
фоновая задача...");
}
public Task
StopAsync(CancellationToken cancellationToken)
{
// Очистка ресурсов
_timer?.Change(Timeout.Infinite, 0);
_timer?.Dispose();
return
Task.CompletedTask;
}
}
2. Зарегистрируйте сервис в DI
В Program.cs (для .NET 6+):
csharp
var builder = Host.CreateApplicationBuilder(args);
// Регистрация
builder.Services.AddHostedService<MyHostedService>();
var host = builder.Build();
host.Run();
Для ASP.NET Core (в Startup.cs или Program.cs):
csharp
services.AddHostedService<MyHostedService>();
3. Запустите приложение
При старте:
- Хост
вызовет StartAsync.
- Ваш таймер
начнёт выполнять DoWork каждые 5 секунд.
- При
остановке (Ctrl+C) будет вызван StopAsync для корректного завершения.
Важные нюансы
- Жизненный
цикл
- StartAsync
выполняется один раз при старте.
- StopAsync
вызывается при:
- завершении работы приложения;
- перезапуске (например, в Kubernetes);
- ручном вызове host.StopAsync().
- Обработка
отмены
Используйте cancellationToken в StopAsync, чтобы: - прервать
длительные операции;
- избежать
утечек памяти.
- Синхронизация
Если в StartAsync есть долгая операция (например, подключение к БД), используйте await — хост дождётся завершения. - Ошибки в StartAsync
Если StartAsync выбрасывает исключение, приложение не запустится. Обрабатывайте ошибки внутри метода.
Альтернатива: BackgroundService
В .NET 3.0+ есть абстрактный класс BackgroundService, который
упрощает реализацию:
csharp
public class MyBackgroundService : BackgroundService
{
protected
override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while
(!stoppingToken.IsCancellationRequested)
{
Console.WriteLine("Работаю в фоне...");
await Task.Delay(5000, stoppingToken);
}
}
}
Плюсы:
- Не нужно
писать StartAsync/StopAsync вручную.
- Встроенная
обработка CancellationToken.
- Подходит
для бесконечных циклов.
Когда выбрать BackgroundService?
Если ваша задача — это цикл с периодическим выполнением
(например, опрос очереди).
Когда выбрать IHostedService?
Если нужна гибкая инициализация (например, дождаться готовности БД) или сложная
логика остановки.
Примеры использования
- Мониторинг
файлов
csharp
public class
FileWatcherService : IHostedService { ... }
- Отправка
уведомлений
csharp
public class
NotificationService : BackgroundService { ... }
- Очистка
временных данных
csharp
public class
TempCleanupService : IHostedService { ... }
- Синхронизация
с внешним API
csharp
public class
ApiSyncService : BackgroundService { ... }
Типичные ошибки
- Забыть
зарегистрировать сервис
Без services.AddHostedService<T>() код не запустится. - Не
обработать CancellationToken
Приложение может зависнуть при остановке. - Блокировать
StartAsync
Долгие операции без await могут привести к таймауту хоста. - Не
очистить ресурсы в StopAsync
Утечки памяти, незакрытые соединения.
Итог
- IHostedService — базовый
интерфейс для фоновых задач с полным контролем над жизненным циклом.
- BackgroundService — удобная
абстракция для циклических задач.
- Регистрация
через DI — обязательный шаг.
- Используйте
CancellationToken для
корректного завершения.
- Обрабатывайте
ошибки в StartAsync, чтобы приложение стартовало.
Правило:
Если задача простая (цикл с
интервалом) — берите BackgroundService. Если нужна сложная
инициализация/остановка — реализуйте IHostedService вручную.
Комментариев нет:
Отправить комментарий