.NET Generic Host - Можно ли остановить и перезапустить хост?

Рассмотрим это чрезвычайно простое приложение .NET Core 3.1 (и .NET 5) без специальной конфигурации или размещенных служб:

using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;

internal class Program
{
    public static async Task Main(string[] args)
    {
        var builder = Host.CreateDefaultBuilder(args);
        builder.UseWindowsService();
        var host = builder.Build();

        var fireAndforget = Task.Run(async () => await host.RunAsync());
        await Task.Delay(5000);
        await host.StopAsync();
        await Task.Delay(5000);
        await host.RunAsync();
    }

Первый запуск (отправленный как фоновый запуск и задача «забыть» только для целей этого теста) и остановка завершаются успешно. При повторном вызове Run я получаю следующее исключение:

System.AggregateException: 'Имя объекта:' EventLogInternal '. Невозможно получить доступ к удаленному объекту. Имя объекта: 'EventLogInternal'.) '

Если я сделаю то же самое, но использую StartAsync вместо RunAsync (на этот раз нет необходимости в fireAndForget), я получаю System.OperationCanceledException при вызове StartAsync во второй раз.

Правильно ли я заключил, что .NET Generic Host не предназначен для остановки и перезапуска?

Зачем мне это нужно?

Моя цель - иметь одно приложение, работающее как службу Windows, на котором размещались бы два разных .NET Generic Host. Это основано на рекомендации здесь, чтобы иметь отдельную конфигурацию и правила внедрения зависимостей и очереди сообщений.

Один будет оставаться активным в течение всего времени существования приложения (до тех пор, пока служба не будет остановлена ​​в службах Windows) и будет служить точкой входа для получения событий сообщений, которые будут запускать / останавливать другой, который будет основным узлом обработки с полными службами. Таким образом, основные службы могут находиться в состоянии ожидания, пока не получат сообщение, запускающее их процесс, а другое сообщение может вернуть их в состояние ожидания.


person Dunge    schedule 02.11.2020    source источник


Ответы (1)


Хост, возвращаемый CreateDefaultBuilder(...).Build(), предназначен для представления всего приложения. Из документов :

Основная причина включения всех взаимозависимых ресурсов приложения в один объект - это управление временем жизни: контроль над запуском приложения и плавным завершением работы.

Конструктор по умолчанию регистрирует многие службы в одноэлементной области, и когда хост останавливается, все эти службы удаляются или переключаются в какое-то состояние остановки. Например, перед вызовом StopAsync вы можете разрешить IHostApplicationLifetime:

var appLifetime = host.Services.GetService<IHostApplicationLifetime>();

У него есть токены отмены, представляющие состояния приложения. Когда вы вызываете StartAsync или RunAsync после остановки, все токены по-прежнему имеют IsCancellationRequested значение true. Вот почему OperactionCancelledException добавлен в Host.StartAsync.

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

Для меня это звучит так, как будто вам просто нужны некоторые фоновые задания для обработки сообщений, но я никогда не использовал NServiceBus, поэтому не знаю, как он будет работать с чем-то вроде Hangfire. Вы также можете реализовать IHostedService и использовать его в универсальном построителе хоста.

person mcbr    schedule 02.11.2020
comment
Спасибо. Таким образом, ответ практически отрицательный, и IHost не предназначен для остановки и перезапуска в течение срока службы приложения. Моя проблема связана с использованием библиотеки, которую я использую, которая вместо предоставления службы в ConfigureService выполняется с помощью метода расширения в IHostBuilder. Вместо этого я свяжусь с ними. - person Dunge; 02.11.2020
comment
Да, короткий ответ - нет :). Я просто не был в этом уверен и проверил исходный код. Технически вы можете создавать хост каждый раз, когда он вам нужен, но это звучит как излишество. - person mcbr; 02.11.2020
comment
К вашему сведению: даже создание нового хоста каждый раз дает сбой с исключением EventLogInternal на второй остановке. То же самое при запуске приложения, закрываемого с помощью ctrl + c. Они действительно не позволяют использовать несколько IHost в одном приложении. - person Dunge; 03.11.2020