如何在C#中序列化一个exception对象?

我想在C#中序列化一个exception对象。 但是,由于Exception类没有标记为[Serializable] ,所以这是不可能的。 有没有办法解决这个问题?

如果在应用程序执行过程中出现问题,我想通知发生的exception。

我的第一个反应是序列化它。

我之前做的是创build一个自定义的错误类。 这封装了关于exception的所有相关信息,并且是可序列化的XML。

 [Serializable] public class Error { public DateTime TimeStamp { get; set; } public string Message { get; set; } public string StackTrace { get; set; } public Error() { this.TimeStamp = DateTime.Now; } public Error(string Message) : this() { this.Message = Message; } public Error(System.Exception ex) : this(ex.Message) { this.StackTrace = ex.StackTrace; } public override string ToString() { return this.Message + this.StackTrace; } } 

使用[Serializable()]属性创build一个自定义的Exception类。 以下是从MSDN取得的一个例子:

 [Serializable()] public class InvalidDepartmentException : System.Exception { public InvalidDepartmentException() { } public InvalidDepartmentException(string message) : base(message) { } public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { } // Constructor needed for serialization // when exception propagates from a remoting server to the client. protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } 

Exception类标记为Serializable并实现ISerializable。 请参阅MSDN: http : //msdn.microsoft.com/en-us/library/system.exception.aspx

如果您试图使用XmlSerializer序列化为XML,那么您将在实现IDictionary任何成员上遇到错误。 这是XmlSerializer的限制,但是这个类肯定是可序列化的。

mson写道:“我不知道为什么你想要序列化例外…”

我序列化exception,通过Web服务将exception通知给可反序列化的调用对象,然后重新抛出,logging或以其他方式处理exception。

我做到了 我简单地创build了一个Serializable包装类,它用一个可序列化的替代(KeyValuePair数组)replaceIDictionary,

 /// <summary> /// A wrapper class for serializing exceptions. /// </summary> [Serializable] [DesignerCategory( "code" )] [XmlType( AnonymousType = true, Namespace = "http://something" )] [XmlRootAttribute( Namespace = "http://something", IsNullable = false )] public class SerializableException { #region Members private KeyValuePair<object, object>[] _Data; //This is the reason this class exists. Turning an IDictionary into a serializable object private string _HelpLink = string.Empty; private SerializableException _InnerException; private string _Message = string.Empty; private string _Source = string.Empty; private string _StackTrace = string.Empty; #endregion #region Constructors public SerializableException() { } public SerializableException( Exception exception ) : this() { setValues( exception ); } #endregion #region Properties public string HelpLink { get { return _HelpLink; } set { _HelpLink = value; } } public string Message { get { return _Message; } set { _Message = value; } } public string Source { get { return _Source; } set { _Source = value; } } public string StackTrace { get { return _StackTrace; } set { _StackTrace = value; } } public SerializableException InnerException { get { return _InnerException; } set { _InnerException = value; } } // Allow null to be returned, so serialization doesn't cascade until an out of memory exception occurs public KeyValuePair<object, object>[] Data { get { return _Data ?? new KeyValuePair<object, object>[0]; } set { _Data = value; } } #endregion #region Private Methods private void setValues( Exception exception ) { if ( null != exception ) { _HelpLink = exception.HelpLink ?? string.Empty; _Message = exception.Message ?? string.Empty; _Source = exception.Source ?? string.Empty; _StackTrace = exception.StackTrace ?? string.Empty; setData( exception.Data ); _InnerException = new SerializableException( exception.InnerException ); } } private void setData( ICollection collection ) { _Data = new KeyValuePair<object, object>[0]; if ( null != collection ) collection.CopyTo( _Data, 0 ); } #endregion } 

如果你试图序列化一个日志的exception,最好做一个.ToString(),然后把它序列化到你的日志中。

但是这里有一篇关于如何做的文章,以及为什么。 基本上,你需要对你的exception实现ISerializable。 如果是系统exception,我相信他们已经实现了这个接口。 如果是别人的例外,你可能可以通过子类来实现ISerializable接口。

为了防止其他人绊倒到这个线程(它是今天Google的第一页),这是一个非常有用的类,用于将一个Exception对象序列化成一个XElement (yay,LINQ)对象:

http://seattlesoftware.wordpress.com/2008/08/22/serializing-exceptions-to-xml/

代码包括完整性:

 using System; using System.Collections; using System.Linq; using System.Xml.Linq; public class ExceptionXElement : XElement { public ExceptionXElement(Exception exception) : this(exception, false) { ; } public ExceptionXElement(Exception exception, bool omitStackTrace) : base(new Func<XElement>(() => { // Validate arguments if (exception == null) { throw new ArgumentNullException("exception"); } // The root element is the Exception's type XElement root = new XElement(exception.GetType().ToString()); if (exception.Message != null) { root.Add(new XElement("Message", exception.Message)); } // StackTrace can be null, eg: // new ExceptionAsXml(new Exception()) if (!omitStackTrace && exception.StackTrace != null) { vroot.Add( new XElement("StackTrace", from frame in exception.StackTrace.Split('\n') let prettierFrame = frame.Substring(6).Trim() select new XElement("Frame", prettierFrame)) ); } // Data is never null; it's empty if there is no data if (exception.Data.Count > 0) { root.Add( new XElement("Data", from entry in exception.Data.Cast<DictionaryEntry>() let key = entry.Key.ToString() let value = (entry.Value == null) ? "null" : entry.Value.ToString() select new XElement(key, value)) ); } // Add the InnerException if it exists if (exception.InnerException != null) { root.Add(new ExceptionXElement(exception.InnerException, omitStackTrace)); } return root; })()) { ; } } 

像这样创build一个protected构造函数(也应该标记你的Exception[Serializable] ):

 protected MyException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context):base(info,context) { } 

我不知道为什么你想要序列化exception…

如果我确实想要做你指定的,我会创build一个实现ISerializable的自定义Exception类。 你可以select使它成为exception的孩子,或者你可以让它成为一个完全自定义的类,只有你所需要的并且做到了。

这是一个古老的线索,但值得另一个答案。

@mson想知道为什么有人想要序列化一个exception。 这是我们做这件事的原因:

我们在Silverlight和WPF中都有一个Prism / MVVM应用程序,在WCF服务中有数据模型。 我们希望确保数据访问和更新无误地发生。 如果出现错误,我们希望立即知道,并告知用户可能失败了。 我们的应用程序将popup一个窗口,通知用户可能的错误。 然后将实际的exception通过电子邮件发送给我们,并存储在SpiceWorks中进行跟踪。 如果错误发生在WCF服务上,我们希望得到完整的exception回到客户端,所以这个过程可能发生。

这里是我提出的解决scheme,可以由WPF和Silverlight客户端来处理。 下面的方法在每个图层中的多个应用程序使用的方法的“Common”类库中。

一个字节数组很容易从WCF服务序列化。 几乎任何对象都可以转换成一个字节数组。

我从两个简单的方法开始,Object2Bytes和Bytes2Object。 这些将任何对象转换为Byte数组并返回。 NetDataContractSerializer来自System.Runtime.Serialization命名空间的Windows版本。

 Public Function Object2Bytes(ByVal value As Object) As Byte() Dim bytes As Byte() Using ms As New MemoryStream Dim ndcs As New NetDataContractSerializer() ndcs.Serialize(ms, value) bytes = ms.ToArray End Using Return bytes End Function Public Function Bytes2Object(ByVal bytes As Byte()) As Object Using ms As New MemoryStream(bytes) Dim ndcs As New NetDataContractSerializer Return ndcs.Deserialize(ms) End Using End Function 

最初,我们将返回所有的结果作为一个对象。 如果从服务返回的对象是一个字节数组,那么我们知道这是一个例外。 然后我们会调用“Bytes2Object”并抛出exception处理。

这个代码的麻烦是,它与Silverlight不兼容。 因此,对于我们的新应用程序,我保留了难以序列化对象的旧方法,并创build了一对仅用于exception的新方法。 DataContractSerializer也来自System.Runtime.Serialization命名空间,但它同时存在于Windows和Silverlight版本中。

 Public Function ExceptionToByteArray(obj As Object) As Byte() If obj Is Nothing Then Return Nothing Using ms As New MemoryStream Dim dcs As New DataContractSerializer(GetType(Exception)) dcs.WriteObject(ms, obj) Return ms.ToArray End Using End Function Public Function ByteArrayToException(bytes As Byte()) As Exception If bytes Is Nothing OrElse bytes.Length = 0 Then Return Nothing End If Using ms As New MemoryStream Dim dcs As New DataContractSerializer(GetType(Exception)) ms.Write(bytes, 0, bytes.Length) Return CType(dcs.ReadObject(ms), Exception) End Using End Function 

当没有错误发生时,WCF服务返回1.如果发生错误,它将Exception传递给一个调用“ExceptionToByteArray”的方法,然后从当前时间生成一个唯一的整数。 它使用该整数作为caching字节数组60秒的关键。 WCF服务然后将密钥值返回给客户端。

当客户端看到它返回一个非1的整数时,它使用该键值调用服务的“GetException”方法。 该服务从caching中获取字节数组并将其发送回客户端。 客户端调用“ByteArrayToException”并像上面描述的那样处理exception。 60秒的时间足以让客户从服务请求exception。 在不到一分钟的时间内,服务器的MemoryCache被清除。

我认为这比创build一个自定义Exception类更容易。 我希望这对以后的人有所帮助。