Async / await和WebException处理

时间:2013-10-16 10:23:46

标签: c# exception-handling async-await

我正在通过使用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会显示异常,并且调试会中断。

任何可以解决异常的合适解决方案?

非常感谢提前。

1 个答案:

答案 0 :(得分:1)

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

  1. async void类型为fire&amp;忘了,只是&amp;仅适用于事件处理程序。
  2. 一旦编译器到达第一个await运算符,异步方法控制就会返回给调用者。
  3. 调试代码: -

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

    如果您在main()内注释掉行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);
        }
    }