Обработка сокетов в ASP.NET Core. Перевод на хостинг IIS

Рейтинг: 1Ответов: 1Опубликовано: 14.06.2023

Есть проект, написанный на ASP.NET Core 3.1 который переехал на .NET 6 (MVC).
В нем есть Kestrel который слушает определенный порт и при новом соединении внешних клиентов с сервером (клиенты представляют себе устройства которые по IP на определенный порт стучаться и передают состояние), может быть сотни подключений, попадает в handler через UseConnectionHandler

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseKestrel(options =>
                {
                    options.ListenAnyIP(7890, _o => _o.UseConnectionHandler<HeadConnectionHandler>());
                    options.ListenAnyIP(80);
                });
                
                webBuilder.UseIISIntegration();
                webBuilder
                    .UseSockets(_s => { _s.NoDelay = false; })                        
                    .UseStartup<Startup>();                    
            });

Есть обычный порт 80 - по которому работает обычный сайт. Проект крутится на виндовом сервере, через публикацию переносимой версии и зависимости от платформы. Запускается через exe в режиме автономности, при запуске exe файла сборки, все работает.

Публикую в IIS, сайт запускается, но прослушивание порта и переход в HeadConnectionHandler - не происходит.
Как правильно настроить работу сервиса, чтобы работал код аналогичный в месте где используется Kestrel?

UPD. I need help :)

Ответы

▲ 0

Вызов UseIISIntegration делает, упрощённо говоря, следующее:

  1. Проверяет переменные окружения ASPNETCORE_*, на наличие
  2. Если их нет - не делает ничего
  3. Если они есть - то затирает настройки конечных точек Kestrel, заставляя его слушать указанный в переменных окружения порт, а также применяет ещё несколько настроек

Если вам надо открыть дополнительный порт с отдельными настройками - это можно сделать примерно так:

  1. Убедитесь что вы создаёте ваш хост либо веб-приложение без настроек по умолчанию, чтобы никто не вызвал UseIISIntegration();
  2. Загляните в исходники UseIISIntegration() чтобы повторить всё то что оно делает - но вручную и без переопределения настроек Kestrel;
  3. Также не забудьте использовать переданные вам переменные окружения в настройках Kestrel;
  4. Когда будете добавлять StartupFilter с вспомогательными мидлварями - не забудьте исключить из его обработки запросы с дополнительной конечной точки (отличить одну конечную точку от другой можно с помощью коллекции Features, которую вы можете менять в вашем HeadConnectionHandler).

Но на самом деле это всё бесполезно, и знаете почему? Потому что IIS отвечает за запуск вашего процесса, и он запустит его только когда придёт запрос на порт 80. То есть, насколько я понял вашу архитектуру, пока первый пользователь не зайдёт на сайт - никакие устройства не смогут передать вам никакое состояние.

Это вообще не то поведение которое нужно в таких случаях!


Как сделать правильно.

Вариант 1:

Откажитесь от прямой публикации в IIS, и запускайте ваш сервер как системную службу, слушающую 127.0.0.1 на нестандартном порту. IIS можно настроить как прокси-сервер без автоматических интеграций.

Вариант 2.

Откажитесь от прямой публикации в IIS, и запускайте ваш сервер как системную службу, слушающую 80й порт напрямую. IIS выкиньте нафиг.

Вариант 3.

Откажитесь от Windows, настройте интеграцию с systemd и запускайте ваш сервер как systemd unit на Linux. Это позволит сэкономить на хостинге если вы хоститесь в облаке.