CancellationToken не запускается при использовании IIS - PullRequest
0 голосов
/ 27 марта 2020

Я знаю, что подобные вопросы задавались здесь десятки раз, но ни один из предоставленных ответов не решил мою конкретную проблему. Поэтому я даю ему еще одну попытку, задавая вопрос сам.

Я работаю над ASP. NET Базовым веб-приложением, работающим на обычном net461 (также пытался net48), где я определил конечную точку HTTP следующим образом:

[HttpGet]
[Route("query/{queryName}")]
public async Task<IActionResult> Call(string queryName, CancellationToken cancellationToken)
{
  await Task.Delay(5_000, cancellationToken);
  ...
}

Поскольку заголовок уже гласит, я не могу заставить cancellationToken вызвать TaskCanceledException при инициировании refre sh на стороне браузера, в то время как первоначальный запрос все еще обрабатывается (Chrome devtools отображает эти события как отмененные запросы). Единственный способ заставить его работать, это выбрать «Project» в настройках отладки Visual Studio (см. Скриншот ниже), что, как мне кажется, заставляет все приложение работать только в Kestrel - без обратного прокси-сервера впереди.

enter image description here

Я встречал различные посты, в которых утверждалось, что эта проблема будет решена с помощью ASP. NET Core 2.2, где внутрипроцессный хостинг должен работать в сочетании с CancellationToken. Поэтому я обновил все свои пакеты nuget, но, к сожалению, безрезультатно, ошибка все еще сохраняется. Да, локально я отлаживаю с помощью IIS Express, и я не уверен, насколько точно это отличается от обычной настройки IIS, но я также запускаю это приложение на Azure, где весь процесс выглядит так, как будто он выполнялся в процессе, потому что запущен только один процесс (см. скриншот ниже).

enter image description here

Это выдержка из моего csproj с пакетами AspNetCore Я установил:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net461</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.13.1" />
    <PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
    <PackageReference Include="Microsoft.AspNetCore.Server.IIS" Version="2.2.6" />
    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" />
    <PackageReference Include="System.Net.Http" Version="4.3.4" />
  </ItemGroup>
</Project>

Я также поиграл с Program.cs, потому что я подозреваю, что это может быть еще одним потенциальным источником ошибки. Я пытался использовать метод расширения UseIIS() только для обеспечения внутрипроцессного хостинга, но также не имел видимого эффекта в отношении CancellationToken:

public class Program
{
    public static void Main(string[] args)
    {
        var host = WebHost.CreateDefaultBuilder(args)
            //.UseKestrel()
            .UseIIS()
            .UseContentRoot(Directory.GetCurrentDirectory())
            //.UseIISIntegration()
            .UseStartup<Startup>()
            .UseApplicationInsights()
            .Build();

        host.Run();
    }
}

Мои вопросы:

  1. Работает ли CancellationToken только с netcoreapp2.x (или выше) в качестве целевой платформы?
  2. Это проблема конфигурации (Program.cs, Startup.cs, csproj, et * 1056) *)?
  3. Можно ли запустить это приложение в Azure Службе веб-приложений на Windows при использовании только Kestrel? Если да, то как мне это настроить?
  4. Есть ли что-то еще, что я мог пропустить, чтобы это сработало?

1 Ответ

0 голосов
/ 05 мая 2020

Короче говоря: оказалось, что служба приложений Azure использует балансировщик нагрузки уровня 7, который НЕ перенаправляет события закрытия соединения в веб-приложение. Таким образом, не имеет значения, используете ли вы веб-приложение Kestrel или внутреннее размещенное в IIS приложение, ваше приложение никогда не получит уведомление.

Очевидное решение - самостоятельно обрабатывать такие события на уровне приложения. Либо путем установки KeepAliveInterval (WebSockets), либо путем прямой подписки на событие закрытия соединения с помощью SignalR.

...