如何从异步方法向调用者抛出异常

本文关键字:调用者 抛出异常 异步方法 | 更新日期: 2023-09-27 17:54:05

今天我读了很多关于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");
    }
}


测试通过,但输出包含:

<>之前系统。异常测试excpetion在AsyncHttpListenerTest.AsyncHttpListener。AsyncHttpListener.cs中的HandleContext(HttpListenerContext context):第30行在AsyncHttpListener.cs中的AsyncHttpListenerTest.AsyncHttpListener.d__0.MoveNext():第25行——抛出异常的前一个位置的堆栈跟踪结束——在System.Runtime.CompilerServices.AsyncMethodBuilderCore。b__1(对象状态)在System.Threading.ExecutionContext。RunInternal(ExecutionContext, ExecutionContext, ContextCallback, callback, Object state, Boolean, preserveSyncCtx)在System.Threading.ExecutionContext。运行(ExecutionContext ExecutionContext, ContextCallback, callback, Object state, Boolean, preserveSyncCtx)在System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem ()在System.Threading.ThreadPoolWorkQueue.Dispatch ()之前

我期望异常将从任务线程(HandleContext()方法)传输到调用者上下文并测试失败。我怎样才能得到这种行为?

如何从异步方法向调用者抛出异常

async void改为async Task,将void改为async Task:

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完成。