dotnet / dotnet/dotnet-api-docs

Undocumented behavior: DNS exception thrown from HttpClient changes threads

Offen
#9,684 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area-System.Threading.Tasks Pri3 untriaged
Vorherrschende Sprache
C#
Sterne
949
Forks
1.7k
Ø Merge
2 T. 19 Std.
Gemergte PRs (30 T.)
52

Beschreibung

Can the documentation be improved to mention this? Maybe I am going crazy, or my code is wrong, but this caused me hours of frustration, (looking for documentation, reviewing my code, and trying different things.)

Worker is started by Task.Factory.StartNew(SAPClientLoop.Worker); The caller was expecting Task.IsCompleted to stay False as long as the worker loop was running, but after the DNS WebException, Task.IsCompleted went to True even though the worker loop was still running, just on a different thread!

If this is fixed in later .NET, that doesn't help me. (Someone else decided Framework 4.8 for the project.)

Source code comments have more explanation of what I think is happening.

```
///
/// The HttpClient worker thread
///
public static async void Worker()
{
//Notes from testing on Framework 4.8
//Note: await async and HttpClient.SendAsync use a Thread pool.
//When an exception is thrown from HttpClient (e.g. DNS lookup error),
//from within a try-catch block, the catch() block may (will?) be
//resumed using a different Thread, after the original thread is just
//stopped without reaching any finally clause. The caller's reference to
//the Task.IsCompleted returns True (would Thread.IsAlive returns False?)
//even though WorkerLoop is still running on the different thread!
//
//It is unknown how any owned synchronization objects would get
//retained or released when the original thread is stopped. To work
//around this behavior, it seems the caller must not use any Task or Thread
//objects, and maintain a WorkerRunning status flag which is
//get, private set so that the caller can test it.
try
{
WorkerRunning = true;
await WorkerLoop(); // Calls .SendAsync with a ".invalid" domain inside a try-catch
WorkerRunning = false; //Not hit
}
catch
{
WorkerRunning = false; //Not hit
}
finally
{
WorkerRunning = false; //Not hit
}
}
```

My WorkerLoop() has logging, this is what is seen. ("[2]" shown in the log entries is the operation ID,
and "startup" is the operation name. Startup is implemented by "Authorize()")

03/06/2024 07:57:46.359 AM,WorkerLoop(),ManagedThreadId =8 IsThreadPoolThread=True
03/06/2024 08:01:52.677 AM,Log(),start[2] (pending 0) startup
03/06/2024 08:01:52.677 AM,ClientLoop.Authorize(),API startup
System.Net.WebException: The remote name could not be resolved: 'api.com.invalid'
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
03/06/2024 08:02:02.005 AM,ClientLoop.Authorize(),API failed.
03/06/2024 08:02:03.794 AM,Log(),finish[2] (pending 0) startup
03/06/2024 08:02:03.794 AM,WorkerLoop(),ManagedThreadId =4 IsThreadPoolThread=True

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Beginne mit den Worker- und WorkerLoop-Einstiegspunkten im Issue, einschließlich des HttpClient.SendAsync-Aufrufs und des aufgezeichneten Thread- und Task.IsCompleted-Verhaltens unter .NET Framework 4.8. Überprüfe das Verhalten und bestimme, welche bestehende API-Dokumentationsseite es erklären sollte; abgeschlossen bedeutet, dass die relevante Dokumentation die beobachtete Ausnahme und das Verhalten der asynchronen Ausführung genau beschreibt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
csharp
Bereich
documentation
Issue-Typ
Dokumentation
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.