HttpClientFactory managed HttpClient deadlocks in single-threaded SynchronizationContext
See original GitHub issueDescribe the bug
my legacy app is still running on ASP.NET, after internal library implementation adopting the HttpClientFactory managed HttpClient, async call with await in HttpClient never returns. this issue is very similar to #563
To Reproduce
dotnet new console -o Console1
cd Console1
dotnet add package Microsoft.Extensions.DependencyInjection --version 2.2.0
dotnet add package Microsoft.Extensions.Http --version 2.2.0
Program.cs
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
namespace Console1
{
public class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddHttpClient();
var provider = services.BuildServiceProvider();
var factory = provider.GetRequiredService<IHttpClientFactory>();
var client1 = new HttpClient();
SingleThreadedSynchronizationContext.Run(() =>
{
Console.Write("default HttpClient in single-threaded SynchronizationContext ... ");
client1.GetAsync("http://example.com").GetAwaiter().GetResult();
Console.WriteLine($"Done");
});
var client2 = factory.CreateClient();
SingleThreadedSynchronizationContext.Run(() =>
{
Console.Write("managed HttpClient in single-threaded SynchronizationContext ... ");
client2.GetAsync("http://example.com").GetAwaiter().GetResult();
Console.WriteLine($"Done");
});
}
}
public class SingleThreadedSynchronizationContext : SynchronizationContext
{
private readonly Queue<(SendOrPostCallback Callback, object State)> _queue = new Queue<(SendOrPostCallback Callback, object State)>();
public override void Post(SendOrPostCallback d, object state)
{
_queue.Enqueue((d, state));
}
public static void Run(Action action)
{
var previous = Current;
var context = new SingleThreadedSynchronizationContext();
SetSynchronizationContext(context);
try
{
action();
while (context._queue.TryDequeue(out var item))
{
item.Callback(item.State);
}
}
finally
{
SetSynchronizationContext(previous);
}
}
}
}
Run this code
$ dotnet run
default HttpClient in single-threaded SynchronizationContext ... Done
managed HttpClient in single-threaded SynchronizationContext ...
you will see the second async call with await in HttpClient hangs
Expected behavior
HttpClientFactory managed HttpClient should also working in single-threaded SynchronizationContext
Screenshots
Additional context
$ dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 2.2.103
Commit: 8edbc2570a
Runtime Environment:
OS Name: Mac OS X
OS Version: 10.14
OS Platform: Darwin
RID: osx.10.14-x64
Base Path: /usr/local/share/dotnet/sdk/2.2.103/
Host (useful for support):
Version: 2.2.1
Commit: 878dd11e62
.NET Core SDKs installed:
2.2.103 [/usr/local/share/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.2.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.2.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.2.1 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (3 by maintainers)
Top Results From Across the Web
HttpClientFactory managed HttpClient deadlocks in single- ...
my legacy app is still running on ASP.NET, after internal library implementation adopting the HttpClientFactory managed HttpClient, async call ...
Read more >How to trigger (NOT avoid!) an HttpClient deadlock
First, SynchronizationContext is not special context we discussed above ... queue and executes them one by one on separate, single thread.
Read more >ConfigureAwait FAQ - .NET Blog
I've heard ConfigureAwait(false) is no longer necessary in .NET Core. True? · SynchronizationContext or · TaskScheduler present. · Task scheduled ...
Read more >Professional C# and .NET [2021 ed.] 1119797209 ...
Chapter 13, “Managed and Unmanaged Memory,” is the last chapter of Part I, which not only shows using the IDisposable interface with the...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
We wouldn’t want that as a dependency in our tests. A simple single threaded sync context could look like this:
Merged the fix. Thanks @akunzai