Подтвердить что ты не робот

Как сериализовать объект Exception в С#?

Я пытаюсь сериализовать объект Exception в С#. Однако кажется, что это невозможно, поскольку класс Exception не помечен как [Serializable]. Есть ли способ обойти это?

Если во время выполнения приложения что-то пошло не так, я хочу получить информацию об исключении, которое произошло.

Мой первый рефлекс - это сериализовать его.

4b9b3361

Ответ 1

То, что я делал ранее, это создать настраиваемый класс ошибок. Это инкапсулирует всю соответствующую информацию об исключении и является сериализуемым 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

Создайте собственный класс исключений с помощью атрибута [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) { }
}

Ответ 3

Класс Exception помечен как Serializable и реализует ISerializable. См. MSDN: http://msdn.microsoft.com/en-us/library/system.exception.aspx

Если вы пытаетесь выполнить сериализацию в XML с помощью XmlSerializer, вы получите ошибку для всех членов, которые реализуют IDictionary. Это ограничение XmlSerializer, но класс, безусловно, сериализуем.

Ответ 4

mson писал: "Я не уверен, почему вы хотите сериализовать исключение..."

Я сериализую исключения, чтобы вызывать исключение через веб-службу вызывающему объекту, который может десериализоваться, а затем ретронировать, регистрировать или иным образом обрабатывать его.

Я сделал это. Я просто создал класс оболочки 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
}

Ответ 5

Если вы пытаетесь сериализовать исключение для журнала, лучше сделать файл .ToString(), а затем сериализовать его в своем журнале.

Но вот статья о том, как это сделать, и почему. В принципе, вам необходимо реализовать ISerializable для вашего исключения. Если это системное исключение, я считаю, что этот интерфейс реализован. Если это чужое исключение, вы можете подклассифицировать его для реализации интерфейса ISerializable.

Ответ 6

На всякий случай кто-то наткнется на этот поток (он на первой странице 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 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 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;
        })())
    { ; }
}

Ответ 7

Создайте конструктор protected, подобный этому (также вы должны отметить свой Exception класс [Serializable]):

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

Ответ 8

Я не уверен, почему вы хотите сериализовать исключение...

Если бы я хотел сделать то, что вы указали, я бы создал пользовательский класс исключений, который реализует ISerializable. Вы можете сделать его дочерним по Исключению, или вы могли бы быть полностью настраиваемым классом, который имеет только то, что вам нужно.

Ответ 9

Это старый поток, но достойный другого ответа.

@mson задавался вопросом, почему кто-то хочет сериализовать Исключение. Вот наша причина для этого:

У нас есть приложение Prism/MVVM с представлениями как в Silverlight, так и в WPF, с моделью данных в службах WCF. Мы хотим быть уверены, что доступ к данным и их обновление происходят без ошибок. Если есть ошибка, мы хотим узнать об этом немедленно и сообщить пользователю, что что-то может потерпеть неудачу. В наших приложениях появится окно, информирующее пользователя о возможной ошибке. Фактическое исключение затем отправляется нам по электронной почте и хранится в SpiceWorks для отслеживания. Если ошибка возникает в службе WCF, мы хотим вернуть полное исключение клиенту, чтобы этот процесс мог произойти.

Вот решение, с которым я столкнулся, который может обрабатываться как WPF, так и Silverlight-клиентами. Методы, приведенные ниже a, в библиотеке классов "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

Изначально мы возвращали бы все результаты как объект. Если объект, возвращающийся из службы, был массивом байтов, то мы знали, что это исключение. Затем мы будем называть "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 очищается.

Я думаю, что это проще, чем создание настраиваемого класса Exception. Надеюсь, это поможет кому-то позже.

Ответ 10

[Сериализуемый] открытый класс CustomException: Exception {public CustomException: (Исключение исключения): base (exception.Message) {
Data.Add("StackTrace",exception.StackTrace); Data.Add( "StackTrace", exception.StackTrace); } }
}

//Для сериализации вашего пользовательского исключения
JsonConvert.SerializeObject(customException);