2014-12-29 18 views
6

Sto creando un'applicazione in cui un client richiede a un server. Il server è scritto in node.js e il client in .NET usando flurl.Http.Flurl.Http errore personalizzato

Quando una richiesta sul server non riesce, è sempre utile creare un messaggio di errore personalizzato. Qualcosa di simile a questo:

request.respond(500, { message: "targetid is mandatory" }); 

Tuttavia, questo richiama una FlurlHttpException sul lato client e le informazioni JSON nella risposta si perde.

Come posso ricevere queste informazioni JSON quando viene ricevuto un responsecode non riuscito dal server?

+0

Penso che la mia [nuova risposta] (http://stackoverflow.com/a/28332184/62600) dovrebbe essere quello che stai cercando. –

risposta

7

Ho appena pubblicato un aggiornamento per Flurl.Http che fa trattare con risposte di errore un bel po ' Più facile.Ecco un esempio:

try { 
    var t = await "http://api.com".GetJsonAsync<T>(); 
} 
catch (FlurlHttpException ex) { 
    var error = ex.GetResponseJson<TError>(); 
} 

Ci sono alcune variazioni:

ex.GetResponseString(); 
ex.GetResponseJson(); // returns a dynamic 

Si noti che non è necessario per il corpo await risposta di errore. Poiché await all'interno di un blocco catch non è supportato in C# 4.5, non lo volevo qui. Non c'è ancora alcun blocco, tuttavia; il corpo della risposta all'errore è atteso e catturato come parte della chiamata originale. (Poiché catturare preventivamente il corpo della risposta come una stringa in circostanze normali potrebbe essere un successo in termini di prestazioni, lo faccio solo per le risposte non riuscite in cui verrà generato un FlurlHttpException. In futuro, potrei considerare di configurare questo comportamento configurabile).

Questi miglioramenti sono stati aggiunti nella versione 0.5.0 e sono disponibili su NuGet.

0

Ho risolto questo problema modificando il codice sorgente di Flurl. Nel file FlurlMessageHandler.cs troverai il metodo IsErrorCondition che controlla se si è verificato un errore. Ogni volta che la risposta non ha il codice 2xx questo è visto come un errore, questa parte l'ho rimossa dal codice e ora controllo manualmente se la risposta ha un codice di successo.

0

è possibile ottenere il corpo della risposta non è riuscito però FlurlHttpException.Call, che è un'istanza di HttpCall, un oggetto di diagnostica che contiene (tra le altre cose) la cruda HttpRequestMessage e HttpResponseMessage.

Ottenere il corpo fuori della risposta richiede una chiamata asincrona, e purtroppo non si può await all'interno di un blocco catch, quindi suggerirei catturare la chiamata fallito all'interno di quel blocco catch e await ing il corpo risposta dopo. Qualcosa di simile a questo:

HttpCall failedCall = null; 

try { 
    await url.GetAsync(); 
} 
catch (FlurlHttpException ex) { 
    failedCall = ex.Call; 
} 

if (failedCall != null && failedCall.Response != null) { 
    var body = await failedCall.Response.Content.ReadAsStringAsync(); 
    // body now contains the full text of the failed response. 
} 

Mentre Flurl eccelle a ottenere è da un URL di base per una risposta POCO con il minor rumore possibile, diventa certamente più rumoroso quando è necessario affrontare con il corpo di una risposta fallito. Ho aperto uno note-to-self per vedere se riesco a trovare alcune scorciatoie qui. Sentiti libero di commentare con qualsiasi idea tu possa avere.

+0

Nella mia risposta mostro come mantenere il flusso asincrono. –

+0

@ LayGonzález Se per "mantenere il flusso asincrono" si intende attendere in un blocco catch, non è possibile farlo nella versione corrente (supportata) della lingua/compilatore, ma capisco [sta arrivando] (http: // blog. stephencleary.com/2014/06/await-in-catch-and-finally.html). –

0

Credo sia interessante gestire tutti gli errori http come eccezioni. Non sono sicuro se sia la migliore pratica, ma ho fatto un tentativo.

Quello che ho fatto è qualcosa di simile:

public static async Task<User> LoginWithEmail (string email, string password){ 
    try{ 
    return await "http://myapi.com/login" 
       .AppendPathSegment ("login") 
       .SetQueryParams (new {email = email, password = password}) 
       .WithHeader ("Accept", "application/json") 
       .GetJsonAsync<User>(); 
    }catch (FlurlHttpException e) { 
    return await e.Call.Response.Content.ReadAsStringAsync() 
        .ContinueWith<User> ((contentAsync) => { 
         throw new MyApiException(JsonConvert.DeserializeObject<MyApiError> (contentAsync.Result)); }); 
    } 
} 

Questo consente di gestire i casi di successo e di errore come questo:

async void FakeLogin() 
{ 
    try{ 
     User user = await LoginWithEmail ("[email protected]", "fakePassword"); 
    } 
    catch(MyApiException e) { 
     MyApiError = e.Error; 
    } 
} 

Fondamentalmente

Per il caso FlurlHttpException , Faccio una continuazione per ReadAsStringAsync dove dichiaro la continuazione per restituire un utente, ma nella continuazione io sempre lanciare un'eccezione

Inoltre

Si potrebbe refactoring l'eccezione manipolazioni devono essere il più breve:

catch (FlurlHttpException e) { 
    return await MyApiException.FromFlurlException<User>(e); 
} 
+0

Quale versione di Visual Studio stai usando? Questo * potrebbe * compilare nell'anteprima 2015 (non ho provato), ma non sarà in alcuna versione supportata perché [non è possibile attendere all'interno di un blocco catch] (http://stackoverflow.com/questions/8868123/await -in-catch-block). –

+0

Sto usando Xamarin's .Net PCL 78, che credo sia .net 4.5. Si compila e viene eseguito, ma ora non sono sicuro è in esecuzione come previsto (asincrono). –

+0

@ToddMenier Ora posso confermare di essere stato in grado di compilarlo perché stavo usando Mono. Visual Studio. Net non consentirà di utilizzare attendere all'interno di un blocco di cattura come hai detto. –

Problemi correlati