En C #, comment puis-je sérialiser System.Exception? (.Net CF 2.0)

Je veux écrire une exception dans une queue de messages MS. Lorsque j’essaie, j’obtiens une exception. J’ai donc essayé de le simplifier en utilisant XmlSerializer qui soulève toujours une exception, mais cela m’a donné un peu plus d’informations:

{“Une erreur est survenue, reflétant le type ‘System.Exception’.”}

avec InnerException:

{“Impossible de sérialiser le membre System.Exception.Data de type System.Collections.IDictionary, car il implémente IDictionary.”}

Exemple de code:

Exception e = new Exception("Hello, world!"); MemoryStream stream = new MemoryStream(); XmlSerializer x = new XmlSerializer(e.GetType()); // Exception raised on this line x.Serialize(stream, e); stream.Close(); 

EDIT: J’ai essayé de garder cela aussi simple que possible, mais je l’ai peut-être exagéré. Je veux le bit entier, la trace de stack, le message, le type d’exception personnalisée et les propriétés d’exception personnalisées. Je peux même vouloir lancer l’exception à nouveau.

Je pense que vous avez essentiellement deux options:

  1. Faites votre propre sérialisation manuelle (probablement ne voulez PAS faire cela). La sérialisation XML ne fonctionnera sûrement pas à cause du message exact que vous obtenez dans l’exception interne.
  2. Créez votre propre classe d’exceptions personnalisée (sérialisable), injectez les données de l’exception levée dans votre classe personnalisée et sérialisez-les.

Je cherchais la réponse de Jason Jackson, mais cela ne me semblait pas logique que j’aie des problèmes avec cela, même si System.Exception implémente ISerializable. J’ai donc contourné XmlSerializer en encapsulant l’exception dans une classe qui utilise à la place un object BinaryFormatter. Lorsque la XmlSerialization des objects MS Message Queuing se déclenche, une classe avec un tableau d’octets public apparaît.

Voici ce que je suis venu avec:

 public class WrappedException { public byte[] Data; public WrappedException() { } public WrappedException(Exception e) { SetException(e); } public Exception GetException() { Exception result; BinaryFormatter bf = new BinaryFormatter(); MemoryStream stream = new MemoryStream(Data); result = (Exception)bf.Deserialize(stream); stream.Close(); return result; } public void SetException(Exception e) { MemoryStream stream = new MemoryStream(); BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(stream, e); Data = stream.ToArray(); stream.Close(); } } 

Le premier test a parfaitement fonctionné, mais je m’inquiétais toujours des exceptions personnalisées. J’ai donc lancé ma propre exception personnalisée. Ensuite, je viens de déposer un bouton sur un formulaire vierge. Voici le code:

 [Serializable] public class MyException : Exception, ISerializable { public int ErrorCode = 10; public MyException(SerializationInfo info, StreamingContext context) : base(info, context) { ErrorCode = info.GetInt32("ErrorCode"); } public MyException(ssortingng message) : base(message) { } #region ISerializable Members void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("ErrorCode", ErrorCode); } #endregion } private void button1_Click(object sender, EventArgs e) { MyException ex = new MyException("Hello, world!"); ex.ErrorCode = 20; WrappedException reply = new WrappedException(ex); XmlSerializer x = new XmlSerializer(reply.GetType()); MemoryStream stream = new MemoryStream(); x.Serialize(stream, reply); stream.Position = 0; WrappedException reply2 = (WrappedException)x.Deserialize(stream); MyException ex2 = (MyException)reply2.GetException(); stream.Close(); Text = ex2.ErrorCode.ToSsortingng(); // form shows 20 // throw ex2; } 

Bien qu’il me semble que tous les autres types d’exceptions que j’ai recherchées sont marqués du SerializableAtsortingbute, je vais devoir faire attention aux exceptions personnalisées qui ne sont pas marquées du SerializableAtsortingbute.

EDIT: Prendre de l’avance sur moi-même. Je n’avais pas réalisé que BinaryFormatter n’était pas implémenté sur CF.

EDIT: Les extraits de code ci-dessus étaient dans un projet de bureau. Dans la version CF, l’exception WrappedException aura fondamentalement la même apparence que celle dont j’ai besoin pour implémenter mon propre BinaryFormater, mais je suis très ouvert aux suggestions à ce sujet.

Commentaire:

La sérialisation des exceptions est une tâche courante lors de la communication à distance ou de l’interaction avec des systèmes au-delà des limites d’un processus. N’écoutez personne qui dit le contraire. ils n’ont probablement jamais écrit une bibliothèque à distance.

Solution:

Je me suis déjà planté à distance pour le faire auparavant en créant une classe d’exception de base personnalisée. Le problème que j’ai rencontré est que System.Exception ne se sérialise pas facilement, donc j’ai dû en hériter. La façon dont j’ai géré cela a été de créer mes propres exceptions qui se sont sérialisées (via ISerializable) et ont encapsulé toute exception System.Exception dans une exception personnalisée.

Dans tout le code de votre serveur, vous devez quand même utiliser des exceptions personnalisées, qui peuvent toutes être basées sur votre type de base sérialisable. Ce n’est pas beaucoup de travail et vous allez rapidement créer une bibliothèque commune d’exceptions.

La couche que vous écrivez dans la queue (et à partir de laquelle vous lisez) doit effectuer toute la sérialisation / l’hydratation des exceptions. Vous pourriez envisager quelque chose comme ceci:

 public class WireObject { public T Payload{get;set;} public E Exception{get;set;} } 

Les couches serveur et client qui communiquent avec votre queue encapsulent l’object que vous envoyez dans la charge utile ou connectent une exception (le cas échéant). Lorsque les données sont consommées à partir de la queue, la couche client peut rechercher une exception et la renvoyer si elle est présente, sinon vous remettre vos données.

C’est une version très simple de ce que j’ai écrit auparavant et de ce que j’ai vu d’autres écrire. Bonne chance pour votre projet.

Pourquoi? Installez-vous une exception après l’avoir extraite de la file de messages? Sinon, envoyez simplement le message d’exception (sous forme de chaîne) …

La sérialisation XML est limitée dans ses utilisations. Par exemple, il ne peut pas sérialiser ce scénario spécifique. Pour la sérialisation exacte et la désérialisation des exceptions, vous devez utiliser un BinaryFormatter , qui fonctionnera aussi longtemps que vos propres exceptions sont marquées [Serializable] . Toutes les exceptions .Net sont marquées avec cet SerializableAtsortingbute , ce qui signifie qu’elles peuvent être sérialisées avec BinaryFormatter .

Il y a cependant un piège à ne pas manquer.
Si votre exception n’est pas sérialisable, elle échouera évidemment. Mais cela échouera également si votre exception contient un champ non sérialisable. Vous devez veiller à ce que cela ne soit pas possible dans vos exceptions personnalisées.

J’ai suivi la méthode suggérée dans ce lien (faites défiler la liste pour trouver la réponse affichée par la personne nommée Kubilay) et cela fonctionne très bien pour moi. Pas besoin de créer de classe wrapper pour l’object exception.

Vous ne pouvez pas sérialiser un dictionnaire en XML. Faites ce que l’autre gars a dit et envoyez le message, c’est l’élément le plus important quand même.