I'm using IdentityModel.OidcClient's SystemBrowser to request a token in a console app via browser. What I don't understand is, why there is an await Task.Delay(500) in the Dispose method of the LoopbackHttpListener. I see why you would do the Dispose via Task.Run, but not the delay.
Line of code in GitHub: https://github.com/IdentityModel/IdentityModel.OidcClient/blob/46d7b25cd71eb0be5f3c203c2525b1f357e408db/clients/ConsoleClientWithBrowser/SystemBrowser.cs#L131
public LoopbackHttpListener(int port, string path = null)
{
path = path ?? String.Empty;
if (path.StartsWith("/")) path = path.Substring(1);
_url = $"http://127.0.0.1:{port}/{path}";
_host = new WebHostBuilder()
.UseKestrel()
.UseUrls(_url)
.Configure(Configure)
.Build();
_host.Start();
}
public void Dispose()
{
Task.Run(async () =>
{
await Task.Delay(500);
_host.Dispose();
});
}
I don't know why that code is used but I can guess. This could only be answered by the maintainers, assuming they still remember why this was written after 6 years.
Clicking on
Blameshows that this specific line is 6 years old, tagged ashacky dispose of Kestrel. Recent commits have messages likeUpdate test clientorUpdate sample client. Thecsprojfile targets .NET 6 directly. If this was library code it would target .NET Standard 2.1 or .NET Core 3.1 as well, which are still supported.My guess is that this code is used to ensure any pending requests handled by the listener complete before it closes. Since this started as test code, some hacks were used and never fixed, because they didn't directly impact the test's or sample's core behavior.
I don't remember what WebHost or the Generic Host looked back in 2017 (and I'm too lazy to find out). The interfaces have changed a lot between .NET Standard 2.0, .NET Core 3.1 and .NET 6.
In .NET 6 though we can use
IAsyncDisposableto allow asynchronous disposal. InsideDisposeAsyncwe can callWebHost.StopAsyncto gracefully shut down the host before disposing it:It's possible the
LoopbackHttpListenercan be replaced by Minimal APIs too.The test code returns a fixed response on any HTTP GET call and exposes the request's query string through the
_sourceTaskCompletionSource.