2015-05-13 4 views
5

Ho un'API Web che rende richieste HTTP a un servizio Windows che esegue determinate attività/comandi.Passaggio di eccezioni tra due programmi C# utilizzando JSON

Se il mio 'servizio' genera un'eccezione, allora voglio passare quell'eccezione eseguendo il backup della pipa sull'API Web utilizzando JSON. Quindi voglio de-serializzare l'eccezione su un oggetto eccezione e lanciarlo.

il mio codice:

eccezione condivisa tra API Web e di servizi:

public class ConnectionErrorException : Exception 
{ 
    public ConnectionErrorException() 
    { 
    } 
    public ConnectionErrorException(String message) 
     : base(message) 
    { 
    } 
} 

Ora nel mio servizio che ho il seguente codice:

 ... 
     try 
     { 
      result = await ExecuteCommand(userId); 
      //If reached here nothing went wrong, so can return an OK result 
      await p.WriteSuccessAsync(); 
     } 
     catch (Exception e) 
     { 
      //Some thing went wrong. Return the error so they know what the issue is 
      result = e; 
      p.WriteFailure(); 
     } 
     //Write the body of the response: 

     //If the result is null there is no need to send any body, the 200 or 400 header is sufficient 
     if (result != null) 
     { 
      var resultOutput = JsonConvert.SerializeObject(result); 
      await p.OutputStream.WriteAsync(resultOutput); 
     } 
     ... 

Così qui ho restituire un oggetto JSON . O l'oggetto della risposta effettiva o l'eccezione che si è verificata.

allora ecco il codice del Web API che rende la richiesta al servizio:

// Make request 
      HttpResponseMessage response = await client.PostAsJsonAsync(((int)(command.CommandId)).ToString(), command); 
      if (response.IsSuccessStatusCode) 
      { 
       return await response.Content.ReadAsStringAsync(); 
      } 
      else 
      { 
       var exception = HandleErrorResponse(await response.Content.ReadAsStringAsync()); 
       var type = exception.GetType(); 
       //TODO: try and determine which exact exception it is. 
       throw exception; 
      } 

Ora qui, se la risposta è stata di successo ho appena restituire il contenuto della stringa. Se la richiesta non riesce, provo a passare la risposta JSON a un'eccezione. Comunque devo passare all'eccezione base come faccio io - non so di che tipo sia ancora. Tuttavia quando eseguo il debug e aggiungo un watchdog all'eccezione. C'è un parametro _className che dice 'Domain.Model.Exceptions.API.ConnectionErrorException`.

Domanda: Come è possibile determinare quale sia la deroga è stato restituito e de-serializzare di nuovo al l'eccezione corretta in modo che posso buttare di nuovo. Devo conoscere il tipo esatto di eccezione perché gestisco tutte le diverse eccezioni più avanti nel mio livello di servizi nell'API Web.

Ecco un esempio di JSON, che viene restituito per la ConnectionErrorException:

{ 
    "ClassName": "Domain.Model.Exceptions.API.ConnectionErrorException", 
    "Message": null, 
    "Data": null, 
    "InnerException": null, 
    "HelpURL": null, 
    "StackTraceString": "", 
    "HResult": -2146233088, 
    "Source": "LinkProvider.Logic", 
    "WatsonBuckets": null 
} 

risposta

1

Si può tenere eccezioni a un C# dynamic oggetto quindi serializzare a JSON e poi tornare dal servizio di Windows. Di nuovo sull'API Web deserializzi quel JSON e tieni un oggetto dinamico. In questo modo non devi preoccuparti del tipo effettivo dell'eccezione. Ad ogni eccezione puoi semplicemente buttarlo via. Se volete sapere il tipo effettivo di eccezione, allora si può scrivere si codifica come questo dove tempData è l'oggetto dynamic dopo deserializiation:

Type exceptionType = ((ObjectHandle)tempData).Unwrap().GetType(); 

E poi gestire l'eccezione di conseguenza

Spero che questo aiuti :)

+0

L'idea è che voglio sapere che tipo di eccezione viene lanciata. Più avanti nel livello dei miei servizi mi occupo di tutti gli errori specifici. Quindi ho bisogno di ottenere il tipo esatto di errore. – Zapnologica

+0

@Zapnologica ha modificato la mia risposta ... questo dovrebbe risolvere il problema – Aminul

1

Prima di tutto per essere in grado di deserializzare eccezione JSON sono stato costretto ad aggiungere un costruttore di più per ConnectionErrorException classe:

public class ConnectionErrorException : Exception 
{ 
    // ... rest of the code 

    protected ConnectionErrorException(SerializationInfo info, StreamingContext context) 
     : base(info, context) 
    { 
    } 
} 

Questo è un problema noto. Controlla questo question per esempio.

Avanti Vorrei leggere prima il valore della proprietà ClassName e poi, in base al valore, lo deserializzerei al tipo desiderato.Penso che sarà una buona idea per creare una classe di supporto per questa:

public static class JsonHelper 
{ 
    public static bool IsInstanceOf<T>(this JsonObject jsonObject) 
    { 
     if (jsonObject == null || !jsonObject.ContainsKey("ClassName")) 
     { 
      return false; 
     } 

     return jsonObject["ClassName"] == typeof(T).FullName; 
    } 
} 

E poi il codice potrebbe essere simile che:

var jsonObject = JsonObject.Parse(json); 
if(jsonObject.IsInstanceOf<ConnectionErrorException>()) 
{ 
    var connectionErrorException = 
     JsonConvert.DeserializeObject<ConnectionErrorException>(json); 
} 
+0

Commento interessante sul costruttore aggiuntivo. Il mio non mi ha dato alcun errore. Grazie per i tuoi aiutanti ti darò una possibilità, sembra un modo pulito per implementarlo. – Zapnologica

+0

È necessario aggiungere quel costruttore extra se si esegue il wrapping dell'eccezione effettiva. –

2

Sostituisci la tua gestione delle eccezioni con blocco di codice seguente.

else 
{ 
    var response = await response.Content.ReadAsStringAsync(); 
    var exception = JsonConvert.DeserializeObject<Exception>(response); 
    // your handling logic here 
    Console.WriteLine(exception); 
} 

Quindi, se il servizio gettò new NotImplementedException("I haz error!"), sopra sarebbe stampare System.NotImplementedException: I haz error!.


Ecco un esempio veloce, stand-alone utilizzando MVVMLight e JSON.net. Diciamo che avete sender come

public class Sender 
{ 
    public Sender() 
    { 
     Messenger.Default.Register<NotificationMessage>(this, message => 
      { 
       if ((Type)message.Target == typeof(Sender)) 
        GotResponse(message.Notification); 
      });  
    } 

    public void SendRequest(string request) 
    { 
     Console.WriteLine("sending:{0}", request); 
     Messenger.Default.Send(
      new NotificationMessage(this, typeof(Receiver), request)); 
    } 

    private void GotResponse(string response) 
    { 
     Console.WriteLine("received:{0}", response); 
     if (response.Equals("ok")) 
      return; 

     Exception exception = JsonConvert.DeserializeObject<Exception>(response); 
     Console.WriteLine("exception:{0}", exception); 

     try 
     { 
      throw exception; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Indeed, it was {0}", e); 
     } 
    } 
} 

e receiver come

public class Receiver 
{ 
    public Receiver() 
    { 
     Messenger.Default.Register<NotificationMessage>(this, message => 
      { 
       if ((Type)message.Target == typeof(Receiver)) 
        GotRequest(message.Notification); 
      }); 
    } 

    public void SendResponse(string response) 
    { 
     Messenger.Default.Send(new NotificationMessage(this, typeof(Sender), response)); 
    } 

    public void GotRequest(string request) 
    { 
     string response = !string.IsNullOrWhiteSpace(request) ? 
          "ok" : 
          JsonConvert.SerializeObject(new NotImplementedException("I haz error!")); 

     SendResponse(response); 
    } 
} 

poi seguendo "attivazione"

var sender = new Sender(); 
var receiver = new Receiver(); 
sender.SendRequest("my request"); 
sender.SendRequest(null); 

sarebbe stampare

invio: la mia richiesta
ricevuti: ok

invio:
ricevuto: { "ClassName": "System.NotImplementedException", "messaggio": "... "" WatsonBuckets": null}

eccezione: System.NotImplementedException: Ho un errore!

In effetti, era System.NotImplementedException: I haz error! a WpfApplication1.View.Sender.GotResponse (String response) in ...

+0

Quindi quello che stai dicendo è che potrei semplicemente fare un '.ToString()' sul mio oggetto e controllare il contenuto della stringa? – Zapnologica

+0

È necessario riformulare il mio commento (ora eliminato). Sto dicendo che devi serializzare l'eccezione usando ad es. JSON.net e poi dall'altra parte solo deserializzare come Exception. –