Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are network exceptions raised by Windows.Web.Http.HttpClient of type System.Exception instead of something more specific?

Whenever I use the Windows.Web.Http.HttpClient class to make HTTP requests, I always handle network exceptions like this:

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

But now I'll catch all exceptions instead of just network exceptions, especially if the try block encompasses more than just the httpClient.GetAsync call.

Various exception HRESULTs are already converted into appropriate managed types automatically at the ABI layer (e.g. E_OUTOFMEMORY is projected to System.OutOfMemoryException), so why are network exceptions not projected in a similar manner?

like image 849
Decade Moon Avatar asked Nov 20 '14 03:11

Decade Moon


2 Answers

There are a very small number of exception types defined by WinRT, and a limited number of HRESULTs that will project specially into C#.

In general, the WinRT API design pattern avoids exceptions for everything except things that are programming errors and should be discovered at design-time (invalid arguments, missing capabilities, etc) or things that you can't really recover from (such as out-of-memory). You should avoid handling these types of exceptions with try \ catch because they represent bugs in your app or an inability of the system to keep running your app.

Instead, WinRT prefers to have methods succeed but return objects with status codes in them (eg, ResponseCode) that you can query to see whether the method completed successfully or not.

The reasoning for this is that many developers fail to handle exceptions (due to not fully testing their app under different configurations). An unhandled exception is guaranteed to bring down the process, which isn't a great experience for customers, but a return value that indicates failure can often be handled by apps, either because they were already checking the status for other reasons (eg, you probably always want to check the HTTP status, whether you got an error or not) or because the code is already resilient to "empty" results (eg, foreach over an empty list is well-defined).

Not all APIs follow this pattern - especially those designed early on in Windows 8 -- but it is a pattern you should see in most WinRT APIs. You will also notice a lot of Try-style APIs in WinRT that attempt to do something and return true or false rather than throwing an exception. So for the most part, your code should be free of try / catch blocks around WinRT API calls, although you might still need to use them for your own code or 3rd-party libraries.

like image 195
Peter Torr - MSFT Avatar answered Nov 09 '22 12:11

Peter Torr - MSFT


I don't know why Windows.Web.Http.HttpClient class exceptions are not automatically wrapped in appropriate managed types, but (thankfully!) there is a method which allows to get the actual reason -- Windows.Web.WebError.GetStatus.

For example:

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.
    }
}
like image 44
Yarik Avatar answered Nov 09 '22 12:11

Yarik