我正在尝试在C#中序列化Exception对象。但是,似乎不可能,因为Exception类未标记为[Serializable]
。有办法解决这个问题吗?
如果在执行应用程序期间出现问题,我希望被告知发生的异常。
我的第一反应是序列化它。
答案 0 :(得分:48)
使用 [Serializable()] 属性创建自定义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) { }
}
答案 1 :(得分:39)
我之前做过的是创建一个自定义的Error类。这封装了有关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;
}
}
答案 2 :(得分:37)
Exception类 标记为Serializable并实现了ISerializable。请参阅MSDN:http://msdn.microsoft.com/en-us/library/system.exception.aspx
如果您尝试使用XmlSerializer
序列化为XML,则会对实施IDictionary
的所有成员发出错误。这是XmlSerializer的限制,但该类当然是可序列化的。
答案 3 :(得分:17)
mson写道:“我不确定你为什么要序列化异常......”
我将异常序列化,通过Web服务将异常冒泡到可以反序列化,然后重新抛出,记录或以其他方式处理它的调用对象。
我这样做了。我只是创建了一个Serializable包装类,用可序列化的替代方法替换IDictionary(KeyValuePair数组)
/// <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
}
答案 4 :(得分:8)
如果您正在尝试序列化日志的异常,那么最好先执行.ToString(),然后将其序列化到您的日志中。
但是here's一篇关于如何做的文章以及原因。基本上,您需要在异常上实现ISerializable。如果它是系统异常,我相信他们已经实现了该接口。如果它是别人的异常,您可以将其子类化以实现ISerializable接口。
答案 5 :(得分:7)
以防其他人偶然发现这个帖子(就像今天的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, e.g.:
// 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;
})())
{ ; }
}
答案 6 :(得分:5)
像这样创建一个protected
构造函数(您也应该标记Exception
类[Serializable]
):
protected MyException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context):base(info,context)
{
}
答案 7 :(得分:1)
我不确定你为什么要序列化异常...
如果我确实想要执行您指定的操作,我将创建一个实现ISerializable的自定义Exception类。你可以选择让它成为Exception的孩子,或者你可以让它成为一个完全自定义的类,它只拥有你所需要的东西。
答案 8 :(得分:1)
这是一个老话题,但值得另一个答案。
@mson想知道为什么有人想序列化异常。这是我们这样做的原因:
我们有一个Prism / MVVM应用程序,在Silverlight和WPF中都有视图,在WCF服务中使用数据模型。我们希望确保数据访问和更新无错误地发生。如果出现错误,我们希望立即了解它,并让用户知道某些内容可能已失败。我们的应用程序将弹出一个窗口,通知用户可能出现的错误。然后将实际的例外情况通过电子邮件发送给我们,并存储在SpiceWorks中进行跟踪。如果在WCF服务上发生错误,我们希望将完整异常返回给客户端,以便进行此过程。
这是我提出的可由WPF和Silverlight客户端处理的解决方案。下面的方法是在每个层中由多个应用程序使用的“公共”类方法库中。
可以从WCF服务轻松序列化字节数组。几乎任何对象都可以转换为字节数组。
我从两个简单的方法开始,Object2Bytes和Bytes2Object。这些将任何对象转换为Byte数组并返回。 NetDataContractSerializer来自Windows版本的System.Runtime.Serialization命名空间。
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”并抛出异常进行处理。
此代码有问题,它与Silverlight不兼容。因此,对于我们的新应用程序,我保留了难以序列化对象的旧方法,并为异常创建了一对新方法。 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”的方法,然后从当前时间生成一个唯一的整数。它使用该整数作为密钥来缓存字节数组60秒。然后,WCF服务将密钥值返回给客户端。
当客户端看到它返回1以外的整数时,它会使用该键值调用Service的“GetException”方法。该服务从缓存中获取字节数组并将其发送回客户端。客户端调用“ByteArrayToException”并处理异常,如上所述。 60秒是客户端从服务请求异常的充足时间。在不到一分钟的时间内,服务器的MemoryCache被清除。
我认为这比创建自定义Exception类更容易。我希望以后这对某人有所帮助。
答案 9 :(得分:0)
我遇到了类似的问题,我需要记录在我的应用程序中抛出的 Exception
的详细信息,但是,它包含一个不可序列化的成员,因此无法序列化。
作为一种解决方法,在 .ToString()
上调用 Exception
方法,该方法返回一个包含 string
详细信息的 Exception
。
string bar;
if (foo is Exception exception)
{
bar = exception.ToString();
}
答案 10 :(得分:-1)
[可序列化]
公共类CustomException:异常
{
公共CustomException:(Exception exception):base(exception.Message)
{
Data.Add(“ StackTrace”,exception.StackTrace);
}
}
//要序列化自定义异常
JsonConvert.SerializeObject(customException);