6

Ogni volta che uso la classe Windows.Web.Http.HttpClient per fare richieste HTTP, ho sempre gestire le eccezioni di rete come questo:Perché le eccezioni di rete vengono generate da Windows.Web.Http.HttpClient di tipo System.Exception invece di qualcosa di più specifico?

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

Ma ora io ti cattura tutte le eccezioni anziché solo eccezioni di rete, soprattutto se il blocco try comprende più di solo la chiamata httpClient.GetAsync.

Varie eccezioni HRESULT sono già convertite automaticamente in tipi gestiti appropriati al livello ABI (ad es. E_OUTOFMEMORY viene proiettato su System.OutOfMemoryException), quindi perché le eccezioni di rete non vengono proiettate in modo simile?

risposta

3

Esistono un numero molto piccolo di tipi di eccezione definiti da WinRT e un numero limitato di HRESULT s che verrà proiettato appositamente in C#.

In generale, l'API modello di progettazione WinRT evita eccezioni per tutto, tranne le cose che sono errori di programmazione e dovrebbe essere scoperti in fase di progettazione (argomenti non validi, le funzionalità mancanti, ecc) o cose che non si può davvero recuperare da (come ad esempio out-of-memory). Dovresti evitare di gestire questi tipi di eccezioni con try \ catch perché rappresentano errori nella tua app o incapacità del sistema di continuare a far funzionare la tua app.

Invece, WinRT preferisce avere metodi riusciti ma restituisce oggetti con codici di stato al loro interno (ad esempio, ResponseCode) che è possibile interrogare per vedere se il metodo è stato completato con successo o meno.

Il ragionamento per questo è che molti sviluppatori non riescono a gestire le eccezioni (a causa di non testare completamente la loro app in diverse configurazioni). Un'eccezione non gestita è garantita per abbattere il processo, che non è una grande esperienza per i clienti, ma un valore di ritorno che indica un errore può essere spesso gestito dalle app, perché già stavano controllando lo stato per altri motivi (es. , probabilmente vuoi sempre controllare lo stato HTTP, se hai o meno un errore) o perché il codice è già resiliente ai risultati "vuoti" (ad esempio, foreach su un elenco vuoto è ben definito).

Non tutte le API seguono questo schema, specialmente quelle progettate in precedenza in Windows 8, ma è uno schema che si dovrebbe vedere nella maggior parte delle API WinRT. Noterai molte API in stile in WinRT che tentano di fare qualcosa e restituiscono true o false invece di lanciare un'eccezione. Quindi, per la maggior parte, il tuo codice dovrebbe essere libero da try/catch blocchi intorno alle chiamate API WinRT, anche se potresti ancora aver bisogno di usarli per il tuo codice personale o per le librerie di terze parti.

+3

Come gestiresti l'esempio nella domanda? L'unico modo sembra essere l'eccezione generale e ispezionare l'HResult. – tagy22

+2

Sì, questo è l'unico vero modo per gestire le eccezioni che non hanno proiezioni specifiche –

+0

Penso che questa sia una buona risposta, ma penso che sarebbe meglio con un po 'di guida in più - come per il commento di tagy22. Per esempio. pensieri sull'uso di response.IsSuccessStatusCode –

3

Non so perché le eccezioni di classe Windows.Web.Http.HttpClient non vengano automaticamente integrate nei tipi gestiti appropriati, ma (per fortuna!) Esiste un metodo che consente di ottenere il motivo reale: Windows.Web.WebError.GetStatus.

Ad esempio:

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

Per quello che vale, ho lottato un po 'per decidere come gestire gli errori (in particolare quelli relativi rete) quando si utilizza Windows.Web.Http.HttpClient in applicazioni UWP.

Il modello ho optato per era quello di restituire un oggetto (che posso tornare utilizzando un task) che contiene sia le informazioni o l'eccezione:

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

    public Exception Exception = null; 
} 

E in particolare, di utilizzare il controllo delle risposte IsSuccessStatusCode proprietà immediatamente dopo aver ricevuto la risposta:

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