0

我正在通过使用 async/await 模式来解决(似乎如此)非常著名的异常处理问题。具体来说,我的上下文是在 HTTP 客户端上,但我也尝试过更简单的测试,它的行为相同。

考虑下面的程序,它是我原始应用程序上下文的超级简化版本。


class Program
{
    static void Main(string[] args)
    {
        Test();

        Console.Write("Press any key...");
        Console.ReadKey();
        Console.WriteLine();
    }


    static async void Test()
    {
        var c = new MyClient();

        try
        {
            var uri = new Uri("http://www.google.com/"); //valid address
            var s = await c.GetString(uri);
            Console.WriteLine(s.Length);
        }
        catch (WebException ex)
        {
            Console.WriteLine(ex.Message);
        }

        try
        {
            var uri = new Uri("http://www.foo.bah/"); //non-existent address
            var s = await c.GetString(uri);
            Console.WriteLine(s.Length);
        }
        catch (WebException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}


class MyClient
{
    public async Task<string> GetString(Uri uri)
    {
        var client = new HttpClient();
        return await client.GetStringAsync(uri);
    }
}

当程序启动时,它将第一个网站的页面作为字符串下载,然后显示其长度:这很好。之后,当对无效地址执行相同的操作时,客户端会引发 WebException(这就是我想要的),但它没有被捕获。

更新:作为“未捕获”,我的意思是代码实际上没有流经“捕获”分支并静默显示异常消息。相反,VS IDE 显示异常,并且调试中断。

捕捉异常的任何体面的解决方案?

提前谢谢了。

4

1 回答 1

1

尽管您已经发现异常HttpRequestException不是WebException,但我仍然想强调一些关于 async-await 运算符用法的重要事项。

  1. async void是 fire & forget 类型,并且仅适用于事件处理程序。
  2. 一旦编译器到达异步方法中的第一个等待运算符,控制就会返回给调用者。

调试您的代码:-

由于您在 Test 方法中使用 async void ,因此控件返回给调用者并继续执行,Console.Write("Press any key...");而没有任何有关 Task 的信息,然后您正在等待用户输入。与此同时,来自 awaited 方法的响应来了,并且在 Test 方法中继续执行。

如果您注释掉Console.ReadKey();main() 中的行或用户立即提供输入,那么您会注意到响应可能会或可能不会被打印出来。这是因为您没有等待任务被执行,您只是相信用户在您的任务完成之前他不会输入任何内容。

解决方案:-

解决方案是从 Test() 返回 Task 然后等待它完成,下面是更新后的代码,还请注意在方法名称末尾添加 Async 是您必须遵循的命名约定,以免您为区分异步和同步而头疼方法。

class Program
{
    static void Main(string[] args)
    {
        Task task = TestAsync();

        Console.Write("Press any key...");
        task.wait();
        //Console.ReadKey();
        Console.WriteLine();
    }


    static async Task<string> TestAsync()
    {
        var c = new MyClient();

        try
        {
            var uri = new Uri("http://www.google.com/"); //valid address
            var s = await c.GetStringAsync(uri);
            Console.WriteLine(s.Length);
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine(ex.Message);
        }

        try
        {
            var uri = new Uri("http://www.foo.bah/"); //non-existent address
            var s = await c.GetStringAsync(uri);
            Console.WriteLine(s.Length);
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine(ex.Message);
        }
         //to avoid compiler error
         return null;
    }
}


class MyClient
{
    public async Task<string> GetStringAsync(Uri uri)
    {
        var client = new HttpClient();
        return await client.GetStringAsync(uri);
    }
}
于 2013-10-17T07:38:24.040 回答