2013-01-17 15 views
7

Dzisiaj dużo czytam o async/poczekać i to całkowicie rozwaliło mój umysł. Nie mogę zrozumieć, dlaczego następujący test minął.Jak rzucić wyjątek do rozmówcy z metody asynchronicznej?

[Test] 
public void Test() 
{ 
    var listener = new AsyncHttpListener(); 
    listener.ListeningAsync(); 

    try 
    { 
     new WebClient().DownloadString("http://localhost:8080/"); 
    } 
    catch (Exception) 
    { 
    } 

    listener.Close(); 
} 

public class AsyncHttpListener 
{ 
    private readonly HttpListener listener; 

    public AsyncHttpListener() 
    { 
     listener = new HttpListener(); 
     listener.Prefixes.Add("http://localhost:8080/"); 
     listener.Start(); 
    } 

    public void Close() 
    { 
     listener.Close(); 
    } 

    public async void ListeningAsync() 
    { 
     var context = await listener.GetContextAsync(); 
     HandleContext(context); 
    } 

    private void HandleContext(HttpListenerContext context) 
    { 
     throw new Exception("test excpetion"); 
    } 
} 


test zaliczony, ale wyjściowy zawiera:

 
System.Exception 
test excpetion 
    at AsyncHttpListenerTest.AsyncHttpListener.HandleContext(HttpListenerContext context) in AsyncHttpListener.cs: line 30 
    at AsyncHttpListenerTest.AsyncHttpListener.d__0.MoveNext() in AsyncHttpListener.cs: line 25 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.AsyncMethodBuilderCore.b__1(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 
    at System.Threading.ThreadPoolWorkQueue.Dispatch() 

się spodziewać, że wyjątek nie zostanie przekazane z nici zadań (metoda HandleContext()) do rozmówcy kontekstu i próby nie. Jak mogę uzyskać to zachowanie?

Odpowiedz

10

Dodać metodę async Task zamiast async void i uczynić metoda badawcza async Task zamiast void:

public async Task ListeningAsync() 
{ 
    var context = await listener.GetContextAsync(); 
    HandleContext(context); 
} 

[Test] 
public async Task Test() 
{ 
    var listener = new AsyncHttpListener(); 
    await listener.ListeningAsync(); 

    try 
    { 
     new WebClient().DownloadString("http://localhost:8080/"); 
    } 
    catch (Exception) 
    { 
    } 

    listener.Close(); 
} 

Istnieje kilka dobrych powodów, aby unikać async void. Obsługa błędów jest jedną z nich. Błędy podniesione z metod async void idą prosto do SynchronizationContext, która była aktualna, gdy metoda się rozpoczęła.

Powodem niepowodzenia testu jest to, że metody async mogą powrócić do swoich rozmówców, zanim zostaną zakończone. Osoba testująca widzi powrót metody testowej (bez odrzucania wyjątku) i oznacza ją jako "przekazaną". Jeśli zwrócisz Task ze swojej metody testowej, osoba testująca wie, aby poczekać, aż Task zostanie ukończona przed rozważeniem ukończenia testu.

Powiązane problemy