As part of setting up the Http2Connection we spin up two background tasks for the read/write channel and in doing so we capture the execution context of the request that initiated the new connection.
We should do the SuppressFlow/RestoreFlow dance somewhere around Http2Connection.SetupAsync. This could also keep it alive.
Repro (note that the finalizer doesn't run until you dispose the client):
var client = new HttpClient
{
DefaultRequestVersion = HttpVersion.Version20
};
await SendRequest(client);
_ = Task.Run(async () =>
{
await Task.Delay(5_000);
Console.WriteLine("Disposing the client");
client.Dispose();
});
for (int i = 1; ; i++)
{
Console.WriteLine(i);
GC.Collect();
GC.WaitForPendingFinalizers();
await Task.Delay(1000);
}
async Task SendRequest(HttpClient client)
{
var asyncLocal = new AsyncLocal<Finalizable>();
asyncLocal.Value = new Finalizable();
await client.GetStringAsync("https://httpbin.org/ip");
}
public sealed class Finalizable
{
~Finalizable() => Console.WriteLine("Finalizer");
}
As part of setting up the
Http2Connectionwe spin up two background tasks for the read/write channel and in doing so we capture the execution context of the request that initiated the new connection.We should do the
SuppressFlow/RestoreFlowdance somewhere aroundHttp2Connection.SetupAsync. This could also keep it alive.Repro (note that the finalizer doesn't run until you dispose the client):