C# 如何从异步方法向调用方抛出异常?

C# 如何从异步方法向调用方抛出异常?,c#,.net,exception-handling,async-await,C#,.net,Exception Handling,Async Await,今天我读了很多关于async/await的文章,这让我大吃一惊。 我不明白为什么下面的测试通过了 [Test] public void Test() { var listener = new AsyncHttpListener(); listener.ListeningAsync(); try { new WebClient().DownloadString("http://localhost:8080/"); } catch (

今天我读了很多关于async/await的文章,这让我大吃一惊。 我不明白为什么下面的测试通过了

[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() 系统异常 测试免除 在AsyncHttpListener.cs中的AsyncHttpListenerTest.AsyncHttpListener.HandleContext(HttpListenerContext上下文):第30行 在AsyncHttpListener.cs中的AsyncHttpListener.d_u0.MoveNext()处:第25行 ---来自引发异常的上一个位置的堆栈结束跟踪--- 在System.Runtime.CompilerServices.AsyncMethodBuilderCore.b__1(对象状态) 位于System.Threading.ExecutionContext.RunInternal(ExecutionContext ExecutionContext、ContextCallback回调、对象状态、布尔值preserveSyncCtx) 在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态,布尔保存SyncCTX) 位于System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()处 在System.Threading.ThreadPoolWorkQueue.Dispatch()中
我希望异常会从任务线程(HandleContext()方法)传输到调用方上下文,然后测试失败。如何获得此行为?

将方法
异步任务
改为
异步无效
,并将测试方法
异步任务
改为
无效

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
方法可能会在完成之前返回给调用方。测试运行程序看到测试方法返回(还没有抛出异常),并将其标记为“已通过”。如果您从测试方法返回
任务
,那么测试运行者知道在考虑测试完成之前等待
任务
完成