I know questions like this have been asked a dozen of times here, but none of the provided answers solved my particular problem. So I'm giving it another try by asking a question myself.
I'm working on a ASP.NET Core web application running on regular net461
(also tried net48
), where I defined an HTTP endpoint like this:
[HttpGet]
[Route("query/{queryName}")]
public async Task<IActionResult> Call(string queryName, CancellationToken cancellationToken)
{
await Task.Delay(5_000, cancellationToken);
...
}
As the title already states, I can't make the cancellationToken
trigger a TaskCanceledException
upon initiating a refresh on browser side, while the initial request is still being processed (Chrome devtools displays these events as cancelled requests). The only way I can make it work, is by selecting "Project" in Visual Studio's Debug settings (see screenshot below), which I guess, makes the whole application run in Kestrel only - without any reverse proxy in front.
I came across various post that claimed this issue would be solved with ASP.NET Core 2.2, where in-process hosting should work in combination with CancellationToken
. So I updated all my nuget packages, but unfortunately with no effect, the error still persists. Yes, locally I'm debugging using IIS Express and I'm not sure how exactly this differs from a regular IIS setup, but I'm also running this app on Azure, where the whole process looks like it was running in-process, because there is only a single process running (see screenshot below).
This is an extract from my csproj with the AspNetCore packages I installed:
<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>
I also played around with the Program.cs, because I suspect this might be another potential source of error. I Tried to use the UseIIS()
extension method only to enforce in-process hosting, but also no visible effect with regard to 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();
}
}
My Questions:
CancellationToken
only work with netcoreapp2.x
(or higher) as target framework?Long story short: It turned out that the Azure App Service is using a level 7 load balancer, which does NOT forward connection-close events to the web app. So it does not matter whether you use a Kestrel or in-process hosted web app on IIS, your app will never get notified.
The obvious solution is to handle such events yourself on application level. Either by setting a KeepAliveInterval
(WebSockets) or by directly subscribing to the connection-closed event using SignalR.