6

每当我使用Windows.Web.Http.HttpClient类发出 HTTP 请求时,我总是像这样处理网络异常:

HttpResponseMessage response;

try
{
    response = await httpClent.GetAsync(new Uri("http://www.microsoft.com"));
}
catch (Exception e)
{
    // Most likely a network exception.
    // Inspect e.HResult value to see what the specific error was.
}

但现在我将捕获所有异常而不仅仅是网络异常,尤其是如果 try 块包含的不仅仅是httpClient.GetAsync调用。

各种异常 HRESULT 已经在 ABI 层自动转换为适当的托管类型(例如 E_OUTOFMEMORY 被投射到 System.OutOfMemoryException),那么为什么网络异常没有以类似的方式投射呢?

4

3 回答 3

3

WinRT 定义的异常类型非常少,并且HRESULT会专门投射到 C# 中的 s 数量有限。

一般来说,WinRT API 设计模式会避免所有异常,除了那些应该在设计时发现的编程错误(无效参数、缺少功能等)或您无法真正恢复的事情(例如 out-内存)。try您应该避免使用\处理这些类型的异常,catch因为它们代表您的应用程序中的错误或系统无法继续运行您的应用程序。

相反,WinRT 更喜欢让方法成功但返回带有状态码的对象(例如ResponseCode),您可以查询这些状态码以查看方法是否成功完成。

原因是许多开发人员无法处理异常(由于没有在不同配置下完全测试他们的应用程序)。一个未处理的异常保证会降低流程,这对客户来说不是一个很好的体验,但是一个指示失败的返回值通常可以由应用程序处理,或者因为他们已经出于其他原因检查状态(例如,你可能总是想检查 HTTP 状态,无论您是否收到错误)或者因为代码已经对“空”结果具有弹性(例如,foreach空列表是明确定义的)。

并非所有 API 都遵循这种模式——尤其是早期在 Windows 8 中设计的那些——但它是您应该在大多数 WinRT API 中看到的模式。您还将注意到TryWinRT 中的许多 -style API 尝试执行某些操作并返回truefalse而不是抛出异常。因此,在大多数情况下,您的代码应该没有围绕 WinRT API 调用的try/catch块,尽管您可能仍需要将它们用于您自己的代码或第 3 方库。

于 2015-01-17T21:53:29.980 回答
3

我不知道为什么Windows.Web.Http.HttpClient类异常不会自动包装在适当的托管类型中,但是(谢天谢地!)有一种方法可以获取实际原因 - Windows.Web.WebError.GetStatus

例如:

using (var client = new HttpClient())
{
    var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.example.com"));

    try
    {
        // Http-errors are returned in the response, and no exception is thrown.
        HttpResponseMessage response = await client.SendRequestAsync(request);
    }
    catch (Exception ex)
    {
        WebErrorStatus error = WebError.GetStatus(ex.HResult);
        // For example, if your device could not connect to the internet at all,
        // the error would be WebErrorStatus.HostNameNotResolved.
    }
}
于 2015-10-09T16:57:07.457 回答
0

对于它的价值,我一直在努力决定在 UWP 应用程序中使用 Windows.Web.Http.HttpClient 时如何处理错误(尤其是与网络相关的错误)。

我确定的模式是返回一个包含信息或异常的对象(我可以使用任务返回):

private class MyResponseObject
{
  public string Data = string.Empty;
  // Alternatively you could return the HttpResponseMessage (I guess).
  //public HttpResponseMessage HttpResponseMessage;

  public Exception Exception = null;
}

具体来说,在获取响应后立即检查响应 IsSuccessStatusCode 属性:

private async Task<MyResponseObject> CallService(Uri url)
{
    MyResponseObject r = new MyResponseObject();

    try
    {
        HttpResponseMessage response = await httpClient.GetAsync(url);

        if (response.IsSuccessStatusCode)
        {
            // do something with the information successfully received
            r.Data = await response.Content.ReadAsStringAsync();
        }
    }
    catch (Exception ex)
    {
        // do something with the exception
        r.Exception = ex;
    }

    return r;
}
于 2017-09-27T20:57:28.497 回答