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 会显示异常,并且调试中断。
有什么像样的解决方案来捕捉异常吗?
提前非常感谢。
尽管您已经发现异常HttpRequestException
不是WebException
,但我仍然想强调有关 async-await 运算符用法的一些重要事项。
-
async void
的类型是 fire & forget,并且仅适用于事件处理程序。 - 一旦编译器到达第一个 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);
}
}