Ich versuche, ein Ausnahmeobjekt in C # zu serialisieren. Es scheint jedoch unmöglich zu sein, da die Ausnahmeklasse nicht als markiert ist [Serializable]
. Gibt es eine Möglichkeit, das zu umgehen?
Wenn während der Ausführung der Anwendung etwas schief geht, möchte ich mit der aufgetretenen Ausnahme informiert werden.
Mein erster Reflex ist, es zu serialisieren.
c#
.net
exception
serialization
Martin
quelle
quelle
System.Exception
Klasse wird als serialisierbar markiert msdn.microsoft.com/en-us/library/…Antworten:
Ich habe zuvor eine benutzerdefinierte Fehlerklasse erstellt. Dies kapselt alle relevanten Informationen zu einer Ausnahme und ist XML-serialisierbar.
[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; } }
quelle
Erstellen Sie eine benutzerdefinierte Ausnahmeklasse mit dem Attribut [Serializable ()] . Hier ist ein Beispiel aus dem 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) { } }
quelle
System.Net.Sockets.SocketException
undSystem.Net.Http.HttpRequestException
NICHT SERIALISIERBAR ?Die Exception-Klasse ist als Serializable gekennzeichnet und implementiert ISerializable. Siehe MSDN: http://msdn.microsoft.com/en-us/library/system.exception.aspx
Wenn Sie versuchen, mithilfe von XML in XML zu serialisieren
XmlSerializer
, wird bei allen implementierten Mitgliedern ein Fehler angezeigtIDictionary
. Dies ist eine Einschränkung des XmlSerializer, aber die Klasse ist sicherlich serialisierbar.quelle
mson schrieb: "Ich bin nicht sicher, warum Sie die Ausnahme serialisieren möchten ..."
Ich serialisiere Ausnahmen, um die Ausnahme über einen Webdienst an das aufrufende Objekt weiterzuleiten, das sie deserialisieren, dann erneut werfen, protokollieren oder auf andere Weise behandeln kann.
Ich tat dies. Ich habe einfach eine serialisierbare Wrapper-Klasse erstellt, die das IDictionary durch eine serialisierbare Alternative ersetzt (KeyValuePair-Array).
/// <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 }
quelle
taste
. DaherBlurgh!
sagt mehr über die Art und Weise Sie sich ausdrücken , dann sagt es über die richtige Code - Formatierung. Aber ich denke, Sie waren sich dessen bereits bewusst ...Data
ein Wert enthalten ist, der nicht serialisiert werden kann?Wenn Sie versuchen, die Ausnahme für ein Protokoll zu serialisieren, ist es möglicherweise besser, .ToString () auszuführen und diese dann in Ihr Protokoll zu serialisieren.
Aber hier ist ein Artikel darüber, wie und warum. Grundsätzlich müssen Sie ISerializable für Ihre Ausnahme implementieren. Wenn es sich um eine Systemausnahme handelt, haben sie meiner Meinung nach diese Schnittstelle implementiert. Wenn es sich um eine Ausnahme einer anderen Person handelt, können Sie diese möglicherweise in Unterklassen unterteilen, um die ISerializable-Schnittstelle zu implementieren.
quelle
Hier ist eine sehr nützliche Klasse zum Serialisieren eines
Exception
Objekts in einXElement
(yay, LINQ) -Objekt:http://seattlesoftware.wordpress.com/2008/08/22/serializing-exceptions-to-xml/
Der Vollständigkeit halber Code enthalten:
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; })()) { ; } }
quelle
Erstellen Sie einen
protected
Konstruktor wie diesen (auch Sie sollten IhreException
Klasse markieren[Serializable]
):protected MyException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context):base(info,context) { }
quelle
Ich bin nicht sicher, warum Sie die Ausnahme serialisieren möchten ...
Wenn ich das tun wollte, was Sie angegeben haben, würde ich eine benutzerdefinierte Ausnahmeklasse erstellen, die ISerializable implementiert. Sie können wählen, ob Sie es zu einem Kind der Ausnahme machen möchten, oder ob es eine vollständig benutzerdefinierte Klasse sein soll, die nur das hat und tut, was Sie benötigen.
quelle
Dies ist ein alter Thread, der jedoch eine andere Antwort verdient.
@mson fragte sich, warum jemand eine Ausnahme serialisieren möchte. Hier ist unser Grund dafür:
Wir haben eine Prism / MVVM-Anwendung mit Ansichten in Silverlight und WPF mit dem Datenmodell in WCF-Diensten. Wir möchten sicherstellen, dass Datenzugriff und Aktualisierungen fehlerfrei erfolgen. Wenn ein Fehler auftritt, möchten wir ihn sofort informieren und den Benutzer darüber informieren, dass möglicherweise ein Fehler aufgetreten ist. Unsere Anwendungen öffnen ein Fenster, das den Benutzer über einen möglichen Fehler informiert. Die eigentliche Ausnahme wird dann per E-Mail an uns gesendet und zur Verfolgung in SpiceWorks gespeichert. Wenn der Fehler bei einem WCF-Dienst auftritt, möchten wir die vollständige Ausnahme an den Client zurückgeben, damit dieser Prozess stattfinden kann.
Hier ist die von mir entwickelte Lösung, die sowohl von WPF- als auch von Silverlight-Clients verarbeitet werden kann. Die folgenden Methoden befinden sich in einer "allgemeinen" Klassenbibliothek von Methoden, die von mehreren Anwendungen in jeder Schicht verwendet werden.
Ein Byte-Array kann einfach von einem WCF-Dienst serialisiert werden. So ziemlich jedes Objekt kann in ein Byte-Array konvertiert werden.
Ich habe mit zwei einfachen Methoden begonnen, Object2Bytes und Bytes2Object. Diese konvertieren jedes Objekt in ein Byte-Array und zurück. NetDataContractSerializer stammt aus der Windows-Version des System.Runtime.Serialization-Namespace.
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
Ursprünglich würden wir alle Ergebnisse als Objekt zurückgeben. Wenn das vom Dienst zurückkommende Objekt ein Byte-Array war, wussten wir, dass es eine Ausnahme war. Dann würden wir "Bytes2Object" aufrufen und die Ausnahme für die Behandlung auslösen.
Das Problem mit diesem Code ist, dass er nicht mit Silverlight kompatibel ist. Für unsere neuen Anwendungen habe ich die alten Methoden für schwer zu serialisierende Objekte beibehalten und nur für Ausnahmen ein paar neue Methoden erstellt. DataContractSerializer stammt ebenfalls aus dem System.Runtime.Serialization-Namespace, ist jedoch sowohl in der Windows- als auch in der Silverlight-Version vorhanden.
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
Wenn keine Fehler auftreten, gibt der WCF-Dienst 1 zurück. Wenn ein Fehler auftritt, übergibt er die Ausnahme an eine Methode, die "ExceptionToByteArray" aufruft, und generiert dann eine eindeutige Ganzzahl aus der aktuellen Zeit. Diese Ganzzahl wird als Schlüssel verwendet, um das Bytearray 60 Sekunden lang zwischenzuspeichern. Der WCF-Dienst gibt dann den Schlüsselwert an den Client zurück.
Wenn der Client feststellt, dass er eine andere Ganzzahl als 1 zurückerhalten hat, ruft er die "GetException" -Methode des Dienstes mit diesem Schlüsselwert auf. Der Dienst ruft das Byte-Array aus dem Cache ab und sendet es an den Client zurück. Der Client ruft "ByteArrayToException" auf und verarbeitet die Ausnahme wie oben beschrieben. 60 Sekunden sind ausreichend Zeit für den Client, um die Ausnahme vom Dienst anzufordern. In weniger als einer Minute wird der MemoryCache des Servers gelöscht.
Ich denke, das ist einfacher als das Erstellen einer benutzerdefinierten Ausnahmeklasse. Ich hoffe, dass dies später jemandem hilft.
quelle
[Serializable] public class CustomException: Exception { public CustomException: ( Exception exception ) : base(exception.Message) { Data.Add("StackTrace",exception.StackTrace); } }
So serialisieren Sie Ihre benutzerdefinierte Ausnahme:
quelle