Async/await and WebException handling

本文关键字:WebException handling and await Async | 更新日期: 2023-09-27 18:35:39

我正在努力解决(似乎如此)通过使用 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(这就是我想要的),但它不会被捕获。

更新:由于"未捕获",我的意思是代码实际上不会流过"catch"分支并静默显示异常消息。相反,VS IDE 会显示异常,并且调试中断。

有什么像样的解决方案来捕捉异常吗?

提前非常感谢。

Async/await and WebException handling

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

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

调试您的代码:-

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

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

溶液:-

解决方案是从 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);
    }
}