我试图在C#中序列化一个异常对象。然而,由于异常类未标记为[Serializable]
,因此似乎不可能进行序列化。是否有方法可以解决这个问题?
如果应用程序执行期间出现问题,我希望通过发生的异常得到通知。
我的第一反应是对其进行序列化。
我试图在C#中序列化一个异常对象。然而,由于异常类未标记为[Serializable]
,因此似乎不可能进行序列化。是否有方法可以解决这个问题?
如果应用程序执行期间出现问题,我希望通过发生的异常得到通知。
我的第一反应是对其进行序列化。
创建带有[Serializable()]属性的自定义异常类。以下是从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) { }
}
System.Net.Sockets.SocketException
和System.Net.Http.HttpRequestException
不可序列化? - Kiquenet异常类被标记为可序列化并实现了ISerializable接口。请参见MSDN:http://msdn.microsoft.com/en-us/library/system.exception.aspx
如果您尝试使用XmlSerializer
将数据序列化为XML,那么任何实现了IDictionary
的成员都会出现错误。这是XmlSerializer的一个限制,但该类确实是可序列化的。
我之前所做的是创建一个自定义错误类。这个类包含了有关异常的所有相关信息,并且可以进行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;
}
}
mson写道:“我不确定为什么你要序列化异常…”
我将异常序列化,通过Web服务将其传递到调用对象,该对象可以反序列化、重新抛出、记录或以其他方式处理它。
我这样做了。我只是创建了一个可序列化的包装类,用可序列化的替代品(KeyValuePair数组)替换了IDictionary。
/// <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
}
如果你要将异常序列化为日志,最好使用.ToString()方法,然后将其序列化到日志中。
但这里有一篇关于如何以及为什么要这样做的文章。基本上,你需要在异常类上实现ISerializable接口。如果是系统异常,我认为它们已经实现了该接口。如果是其他人的异常,你可以尝试继承它来实现ISerializable接口。
Exception
对象序列化为XElement
对象的非常有用的类(使用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;
})())
{ ; }
}
protected
构造函数(同时你应该将你的Exception
类标记为[Serializable]
):protected MyException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context):base(info,context)
{
}
我曾经遇到过类似的问题,需要记录应用程序中抛出的异常细节,但是它包含了一个非可序列化的成员,因此无法进行序列化。
为了解决这个问题,可以通过调用Exception
的.ToString()
方法来返回包含Exception
细节的字符串。
string bar;
if (foo is Exception exception)
{
bar = exception.ToString();
}
这是一个旧的帖子,但值得再次回答。
@mson想知道为什么有人想序列化异常。以下是我们这样做的原因:
我们有一个使用Prism/MVVM的应用程序,其中视图在Silverlight和WPF中都有,数据模型在WCF服务中。我们希望确保数据访问和更新不会出错。如果出现错误,我们希望立即得知,并让用户知道可能发生了某些故障。我们的应用程序将弹出一个窗口,通知用户可能出现错误。然后,实际的异常将通过电子邮件发送给我们,并存储在SpiceWorks中进行跟踪。如果错误发生在WCF服务上,我们希望将完整的异常返回给客户端,以便进行此过程。
以下是我想出的解决方案,可以由WPF和Silverlight客户端处理。下面的方法在多个应用程序的“Common”类库中使用。
从WCF服务轻松序列化字节数组。几乎任何对象都可以转换为字节数组。
我从两个简单的方法Object2Bytes和Bytes2Object开始。这些方法将任何对象转换为字节数组并返回。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
最初,我们会将所有的结果作为一个 Object 返回。如果从服务返回的对象是字节数组,则说明它是异常。然后我们会调用“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。如果发生错误,则将异常传递给调用“ExceptionToByteArray”的方法,然后从当前时间生成一个唯一的整数。它使用该整数作为键来缓存字节数组60秒钟。然后,WCF服务将键值返回给客户端。
当客户端看到返回的整数不是1时,它使用该键值调用服务的“GetException”方法。服务从缓存中获取字节数组并将其发送回客户端。客户端调用“ByteArrayToException”并按我上面描述的方式处理异常。60秒足够客户端从服务请求异常。在不到一分钟的时间内,服务器的MemoryCache就会被清除。
我认为这比创建自定义异常类更容易。我希望这对以后的某些人有所帮助。
我不确定为什么您想要序列化异常...
如果我确实想要执行您指定的操作,我会创建一个实现ISerializable接口的自定义异常类。您可以选择将其作为Exception的子类,或者您可以将其作为完全自定义的类,只具有并执行您需要的功能。
System.Exception
类被标记为可序列化。https://msdn.microsoft.com/zh-cn/library/system.exception(v=vs.110).aspx - Jodrell