在C#中,如何序列化System.Exception? (.Net CF 2.0)

我想写一个MS Message Queue的exception。 当我尝试它时,我得到一个例外。 所以我尝试使用仍然引发exception的XmlSerializer来简化它,但它给了我更多信息:

{“反映类型’System.Exception’时出错。”}

与InnerException:

{“无法序列化System.Collections.IDictionary类型的成员System.Exception.Data,因为它实现了IDictionary。”}

示例代码:

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(); 

编辑:我尽量保持这个简单,但我可能已经过度了。 我想要整个位,堆栈跟踪,消息,自定义exception类型和自定义exception属性。 我甚至可能想再次抛出exception。

我认为你基本上有两个选择:

  1. 做你自己的手动序列化(可能不想这样做)。 由于您在内部exception中获得的确切消息,XML序列化肯定无法工作。
  2. 创建自己的自定义(可序列化)exception类,将抛出的exception中的数据注入到自定义exception类中并对其进行序列化。

我正在看杰森jackson的答案,但即使System.Exception实现了ISerializable,我也没有理由对我有这个问题。 因此,我通过将exception包装在使用BinaryFormatter的类中来绕过XmlSerializer。 当MS消息队列对象的XmlSerialization全部启动时,它将看到一个带有公共字节数组的类。

这就是我想出的:

 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(); } } 

第一次测试工作得很好,但我仍然担心自定义exception。 所以我把我自己的自定义exception抛在一起。 然后我只是在空白表格上放了一个按钮。 这是代码:

 [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(string 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.ToString(); // form shows 20 // throw ex2; } 

虽然看起来我查找的所有其他exception类型都标有Seri​​alizableAttribute,但我必须要小心未使用SerializableAttribute标记的自定义exception。

编辑:超越自己。 我没有意识到在CF上没有实现BinaryFormatter。

编辑:上面的代码片段在桌面项目中。 在CF版本中,WrappedException基本上看起来与我需要实现自己的BinaryFormater相同,但我对这一点的建议非常开放。

评论:

在跨进程边界进行远程处理或与系统交互时,序列化exception是一项常见任务。 不要听别人说的话; 他们可能从未写过远程库。

解:

我之前通过创建自定义的基本exception类来检测远程执行操作。 我遇到的问题是System.Exception不容易序列化,所以我不得不inheritance它。 我处理这个问题的方法是创建自己的exception序列化(通过ISerializable),并在自定义exception中包装任何System.Exception。

在整个服务器代码中,您应该使用自定义exception,这些都可以基于您的可序列化基本类型。 这项工作并不多,您将很快建立一个共同的例外库。

您写入队列(并从中读取)的层应该执行所有exception序列化/水合作用。 你可能会考虑这样的事情:

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

与队列通信的服务器和客户端层将包装您在Payload中发送的对象,或附加exception(如果有)。 当从队列中消耗数据时,客户端层可以检查exception并在存在时重新抛出,否则将数据提交给您。

这是我之前写过的一个非常简单的版本,以及我看到别人写的内容。 祝你的项目好运。

为什么? 您是否在从消息队列中检索exception时实例化exception? 如果没有,只需发送exception消息(作为字符串)…

嗯,XML序列化的用途有限。 例如,它无法序列化此特定方案。 对于Exceptions的精确序列化和反序列化,您必须使用BinaryFormatter ,只要您自己的exception标记为[Serializable] ,它就会起作用。 所有.Netexception都使用此SerializableAttribute标记,这意味着它们可以使用BinaryFormatter进行序列化。

不过,你必须注意那里有一个问题。
如果您的exception不可序列化,则显然会失败。 但是当您的exception包含一个不可序列化的字段时,它也会失败。 您应注意确保在自定义例外中无法实现。

我按照此链接中建议的方法(向下滚动以查找名为Kubilay的人发布的答案),这对我来说很有用。 无需为exception对象创建任何包装类。

您无法将字典序列化为xml。 做其他人所说的并发送信息,无论如何这是重要的一点。