为什么System.Exception类型的Windows.Web.Http.HttpClient引发网络异常而不是更具体的东西?

时间:2014-11-20 03:50:05

标签: c# windows-runtime windows-phone-8.1 windows-8.1 winrt-httpclient

每当我使用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),那么为什么不以类似的方式预测网络异常?

3 个答案:

答案 0 :(得分:3)

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

通常,WinRT API设计模式避免除了编程错误之外的所有内容的异常,并且应该在设计时发现(无效参数,缺少功能等)或者你可以发现的东西真的从中恢复(比如内存不足)。您应该避免使用try \ catch处理这些类型的例外,因为它们代表了您应用中的错误或系统无法继续运行您的应用。

相反,WinRT更喜欢让方法成功但返回其中包含状态代码的对象(例如ResponseCode),您可以查询该方法是否成功完成。

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

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

答案 1 :(得分:3)

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

例如:

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.
    }
}

答案 2 :(得分:0)

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

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

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;
}