2013-01-17 74 views
7

今天我讀了很多關於異步/等待的信息,它完全讓我失去了主意。 我不明白爲什麼下面的測試通過。如何從異步方法向調用者拋出異常?

[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"); 
    } 
} 


測試通過,但輸出包含:

 
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() 

我期望例外將從任務線程傳輸(HandleContext()方法)至呼叫者上下文和測試失敗。我如何得到這種行爲?

回答

10

讓你的方法async Task而不是async void,並讓您的測試方法,而不是async Taskvoid

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(); 
} 

有幾個很好的理由,以避免async void。錯誤處理就是其中之一。從async void方法中產生的錯誤直接進入方法開始時最新的SynchronizationContext

您的測試通過的原因是因爲async方法可能會在完成之前返回到其調用方。測試運行者看到測試方法返回(沒有拋出異常),並將其標記爲「已通過」。如果您從測試方法中返回Task,則在考慮測試完成之前,測試運行人員知道要等待Task完成。