dotnet / dotnet/dotnet-api-docs

Undocumented behavior: DNS exception thrown from HttpClient changes threads

Aperta
#9,684 3 commenti 0 reazioni 0 assegnatari Vedi su GitHub
area-System.Threading.Tasks Pri3 untriaged
Lingua principale
C#
Stelle
949
Fork
1.7k
Merge medio
2g 19h
PR unite (30g)
52

Descrizione

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

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Inizia dai punti di ingresso Worker e WorkerLoop dell’issue, inclusa la chiamata a HttpClient.SendAsync e il comportamento registrato del thread e di Task.IsCompleted su .NET Framework 4.8. Verifica il comportamento e determina quale pagina esistente della documentazione dell’API dovrebbe spiegarlo; il lavoro è completato quando la documentazione pertinente descrive accuratamente l’eccezione osservata e il comportamento dell’esecuzione asincrona.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
csharp
Ambito
documentation
Tipo di issue
Documentazione
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Da chiarire
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.