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

Whenever I use the Windows.Web.Http.HttpClient class to execute HTTP requests, I always handle network exceptions as follows:

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 will catch all exceptions instead of network exceptions, especially if the try block includes more than just calling httpClient.GetAsync .

Various HRESULT exceptions are automatically converted to the corresponding managed types at the ABI level (for example, E_OUTOFMEMORY is projected onto System.OutOfMemoryException), so why aren't network exceptions projected in the same way?

+6
source share
3 answers

There are a very small number of exception types defined by WinRT, and a limited number of HRESULT that will be specifically designed for C #.

In general, the WinRT API design pattern avoids exceptions for everything except things that are programming errors and should be opened at design time (invalid arguments, missing features, etc.) or things that you really cannot recover from ( such as out of memory). You should avoid handling these types of exceptions with try \ catch , because they represent errors in your application or the inability of the system to continue running your application.

Instead, WinRT prefers the methods to succeed, but return objects with a status in them (for example, ResponseCode ), which you can request to see if this method succeeds.

The reason for this is that many developers cannot handle exceptions (due to the fact that they do not fully test their application in different configurations). An unhandled exception is guaranteed to reduce the process, which is not a great experience for clients, but the return value indicating failure can often be processed by applications either because they already check the status for other reasons (for example, you probably always want to check the status of HTTP, there is whether you have an error or not) or because the code is already resistant to "empty" results (for example, foreach is clearly defined on empty lists).

Not all APIs follow this pattern - especially those that were developed early on in Windows 8, but this is the pattern that you should see in most WinRT APIs. You will also notice many try style WinRT APIs that try to do something and return true or false , rather than throw an exception. Therefore, for the most part, your code should be free of try / catch blocks around WinRT API calls, although you still have to use them for your own code or third-party libraries.

+3
source

I do not know why Windows.Web.Http.HttpClient class exceptions are not automatically wrapped in the corresponding managed types, but (fortunately!) There is a method that allows you to get the actual reason - Windows.Web.WebError.GetStatus .

For instance:

 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. } } 
+3
source

For what it's worth, I tried a bit to decide how to handle errors (especially network-related) when using Windows.Web.Http.HttpClient in UWP applications.

The sample that I stopped at was to return an object (which I can return using a task) that contains either information or an exception:

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

And, in particular, to immediately check the response to the IsSuccessStatusCode property after receiving the response:

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

Source: https://habr.com/ru/post/978433/


All Articles