четверг, 12 февраля 2026 г.

26.02.13 Alice, BackgroundService, Net, AspNet

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.

Как начать проект: пошаговый алгоритм

  1. Создайте проект:

bash

dotnet new webapi -n MyProject

  1. Определите интерфейсы и классы в папке Services/.
  2. Зарегистрируйте сервисы в Program.cs:

csharp

builder.Services.AddScoped<IUserService, UserService>();

  1. Добавьте фоновые задачи (если нужно):

csharp

builder.Services.AddHostedService<DataProcessorService>();

  1. Настройте конфигурацию через appsettings.json.
  2. Запустите:

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:

  1. Создайте файл appsettings.json в корне проекта:

json

{

  "WorkerSettings": {

    "IntervalSeconds": 10,

    "Message": "Hello from config!"

  }

}

  1. Добавьте класс для настроек:

csharp

public class WorkerSettings

{

    public int IntervalSeconds { get; set; }

    public string Message { get; set; }

}

  1. Внедрите настройки в 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);

        }

    }

}

  1. Зарегистрируйте настройки в 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. Запуск и тестирование

  1. Соберите проект:

bash

dotnet build

  1. Запустите:

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!

...

  1. Остановить сервис: нажмите 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+ и т. д.

Ключевые факты

  1. Независимость от веб‑стека
    BackgroundService можно использовать в:
    • консольных приложениях;
    • сервисах Windows;
    • приложениях IoT;
    • любых не‑веб проектах .NET.
  2. Где он определён
    Сборка:
    Microsoft.Extensions.Hosting.Abstractions.dll
    Пространство имён:
    Microsoft.Extensions.Hosting
    (не
    Microsoft.AspNetCore.*!).
  3. Как подключается
    Пакет
    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();

Почему возникает путаница

  1. Шаблоны ASP.NET Core включают Microsoft.Extensions.Hosting
    В веб‑проектах этот пакет подтягивается автоматически, поэтому кажется, что
    BackgroundService — «веб‑фича».
  2. Общая экосистема .NET
    Многие компоненты (DI, конфигурация, логирование) едины для всех типов приложений .NET.
    BackgroundService — один из них.
  3. Документация часто показывает примеры в контексте 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 в любом из проектов:

  1. Создайте файл appsettings.json:

json

{

  "PollInterval": 7000

}

  1. Добавьте класс настроек:

csharp

public class AppSettings

{

    public int PollInterval { get; set; }

}

  1. В 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();

  1. В сервисе используйте настройки:

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

Действия:

  1. Откройте в браузере http://localhost:5000 — увидите страницу с сообщениями.
  2. В консоли будут логи обмена между сервисами.
  3. Сообщения из BackgroundServiceA/B транслируются в браузер через SignalR.

Ключевые различия между проектами

Параметр

Чистый .NET

ASP.NET Core

Веб‑сервер

Нет

Да (Kestrel)

SignalR‑доступность

Только внутри процесса

Доступно извне (через /chatHub)

Клиент для SignalR

Нужен внешний (например, JS‑браузер)

Встроенный HTML‑клиент

HTTP‑эндпоинты

Нет

Да (/ и /chatHub)

Сценарии использования

Автономный фоновый процесс

Веб‑приложение + фоновые задачи


Как это работает

  1. Фоновые сервисы (A и B) запускаются при старте приложения.
  2. Каждый сервис:
    • отправляет сообщение соседу (через метод ReceiveMessageFromX);
    • выводит сообщение в консоль;
    • транслирует

        Почему я задаю такие вопросы. Потому что часто бывают ситуации когда ты написал проект, создал свои сущности. А потом оказывается, что такие сущности уже есть из коробки для проектов .Net и ASp NetCore

    Вы задаёте абсолютно правильные вопросы — и ваша настороженность полностью оправдана. Это один из ключевых навыков опытного разработчика: не изобретать велосипед, а сначала выяснить, что уже есть «из коробки».

Разберём, почему так происходит и как этому противостоять.

Почему мы часто «переизобретаем» решения

  1. Фрагментарное обучение
    Часто изучаем отдельные технологии (например, «только ASP.NET Core»), не видя всей экосистемы .NET.
  2. Доминирование веб‑контекста
    Большинство туториалов — про веб. Отсюда иллюзия, что
    BackgroundService — «веб‑фича».
  3. Скрытые зависимости
    Многие «стандартные» классы (как
    BackgroundService) живут в пакетах типа Microsoft.Extensions.*, которые подключаются неявно через шаблоны проектов.
  4. Отсутствие карты экосистемы
    Нет единого справочника: «Вот все встроенные механизмы .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

Перед установкой сторонней библиотеки:

  1. Поищите в по названию задачи.
  2. Проверьте, не входит ли нужное в 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).

Вывод

Ваш подход — идеальный. Перед реализацией:

  1. Спросите: «Есть ли это в .NET/ASP.NET Core из коробки?»
  2. Проверьте документацию и исходники.
  3. Изучите шаблоны проектов.
  4. Поищите в 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. Запустите приложение

При старте:

  1. Хост вызовет StartAsync.
  2. Ваш таймер начнёт выполнять DoWork каждые 5 секунд.
  3. При остановке (Ctrl+C) будет вызван StopAsync для корректного завершения.

Важные нюансы

  1. Жизненный цикл
    • StartAsync выполняется один раз при старте.
    • StopAsync вызывается при:
      • завершении работы приложения;
      • перезапуске (например, в Kubernetes);
      • ручном вызове host.StopAsync().
  2. Обработка отмены
    Используйте
    cancellationToken в StopAsync, чтобы:
    • прервать длительные операции;
    • избежать утечек памяти.
  3. Синхронизация
    Если в
    StartAsync есть долгая операция (например, подключение к БД), используйте await — хост дождётся завершения.
  4. Ошибки в 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?
Если нужна гибкая инициализация (например, дождаться готовности БД) или сложная логика остановки.

Примеры использования

  1. Мониторинг файлов

csharp

public class FileWatcherService : IHostedService { ... }

  1. Отправка уведомлений

csharp

public class NotificationService : BackgroundService { ... }

  1. Очистка временных данных

csharp

public class TempCleanupService : IHostedService { ... }

  1. Синхронизация с внешним API

csharp

public class ApiSyncService : BackgroundService { ... }

Типичные ошибки

  1. Забыть зарегистрировать сервис
    Без
    services.AddHostedService<T>() код не запустится.
  2. Не обработать CancellationToken
    Приложение может зависнуть при остановке.
  3. Блокировать StartAsync
    Долгие операции без
    await могут привести к таймауту хоста.
  4. Не очистить ресурсы в StopAsync
    Утечки памяти, незакрытые соединения.

Итог

  • IHostedService — базовый интерфейс для фоновых задач с полным контролем над жизненным циклом.
  • BackgroundService — удобная абстракция для циклических задач.
  • Регистрация через DI — обязательный шаг.
  • Используйте CancellationToken для корректного завершения.
  • Обрабатывайте ошибки в StartAsync, чтобы приложение стартовало.

Правило:

Если задача простая (цикл с интервалом) — берите BackgroundService. Если нужна сложная инициализация/остановка — реализуйте IHostedService вручную.


Комментариев нет:

Отправить комментарий