Как в C# сериализовать System.Exception? (.Net CF 2.0)

Я хочу записать исключение в очередь сообщений MS. Когда я пытаюсь это сделать, я получаю исключение. Поэтому я попытался упростить его, используя XmlSerializer, который по-прежнему вызывает исключение, но дал мне немного больше информации:

{"There was an error reflecting type 'System.Exception'."}

с InnerException:

{"Cannot serialize member System.Exception.Data of type System.Collections.IDictionary, because it implements IDictionary."}

Образец кода:

        Exception e = new Exception("Hello, world!");
        MemoryStream stream = new MemoryStream();
        XmlSerializer x = new XmlSerializer(e.GetType()); // Exception raised on this line

        x.Serialize(stream, e);
        stream.Close();

Обновлено: Я старался сделать это как можно проще, но, возможно, переборщил. Мне нужен весь бит, трассировка стека, сообщение, настраиваемый тип исключения и настраиваемые свойства исключения. Возможно, я даже захочу снова выбросить исключение.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
19
0
20 170
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Почему? Вы создаете экземпляр исключения при его извлечении из очереди сообщений? Если нет, просто отправьте сообщение об исключении (в виде строки) ...

Или, что еще лучше, отправьте свойство StackTrace в виде строки

Rich 23.12.2008 23:56

> Вы создаете экземпляр исключения при его извлечении из очереди сообщений? Да.

CrashCodes 24.12.2008 00:06

Вы не можете сериализовать словарь в xml. Сделайте то, что сказал другой парень, и отправьте сообщение, это в любом случае важный момент.

Ответ принят как подходящий

Я думаю, у вас в основном есть два варианта:

  1. Сделайте свою собственную сериализацию вручную (вероятно, НЕ хотите этого делать). Сериализация XML, безусловно, не будет работать из-за точного сообщения, которое вы получаете во внутреннем исключении.
  2. Создайте свой собственный (сериализуемый) класс исключений, вставьте данные из созданного исключения в свой собственный и сериализуйте их.

Комментарий:

Сериализация исключений - это обычная задача при удаленном взаимодействии с системами через границы процессов. Не слушайте никого, кто говорит иначе; они, вероятно, никогда не писали удаленную библиотеку.

Решение:

Для этого я уже использовал удаленное взаимодействие, создав собственный базовый класс исключений. Проблема, с которой я столкнулся, заключалась в том, что System.Exception не сериализуется легко, поэтому мне пришлось наследовать от него. Я справился с этим путем создания собственных исключений, которые сериализовались (через ISerializable) и заключили любое System.Exception в настраиваемое исключение.

Во всем коде сервера вы в любом случае должны использовать настраиваемые исключения, и все они могут быть основаны на вашем сериализуемом базовом типе. Это не так уж и много работы, и вы быстро создадите общую библиотеку исключений до конца.

Слой, который вы записываете в очередь (и читаете из него), должен выполнять сериализацию / гидратацию всех исключений. Вы можете подумать о чем-то вроде этого:

public class WireObject<T, E>
{
  public T Payload{get;set;}
  public E Exception{get;set;}
}

Серверный и клиентский уровни, которые общаются с вашей очередью, заключат объект, который вы отправляете, в Payload или присоединят исключение (если есть). Когда данные потребляются из очереди, клиентский уровень может проверить наличие исключения и повторно выбросить его, если оно есть, иначе передать вам ваши данные.

Это очень простая версия того, что я писал раньше и что я видел, как пишут другие. Удачи с проектом.

Я смотрел на ответ Джейсона Джексона, но для меня не было смысла в том, что у меня проблемы с этим, хотя System.Exception реализует ISerializable. Поэтому я обошел XmlSerializer, заключив исключение в класс, который вместо этого использует BinaryFormatter. Когда XmlSerialization объектов очереди сообщений MS сработает, все, что он увидит, - это класс с публичным массивом байтов.

Вот что я придумал:

public class WrappedException {
    public byte[] Data;

    public WrappedException() {
    }

    public WrappedException(Exception e) {
        SetException(e);
    }

    public Exception GetException() {
        Exception result;
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream stream = new MemoryStream(Data);
        result = (Exception)bf.Deserialize(stream);
        stream.Close();
        return result;
    }

    public void SetException(Exception e) {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(stream, e);
        Data = stream.ToArray();
        stream.Close();
    }
}

Первый тест прошел отлично, но меня по-прежнему беспокоили настраиваемые исключения. Итак, я собрал собственное исключение. Затем я просто нажал кнопку на пустой форме. Вот код:

[Serializable]

public class MyException : Exception, ISerializable {
    public int ErrorCode = 10;
    public MyException(SerializationInfo info, StreamingContext context)
        : base(info, context) {

        ErrorCode = info.GetInt32("ErrorCode");
    }

    public MyException(string message)
        : base(message) {
    }

    #region ISerializable Members
    void ISerializable.GetObjectData(SerializationInfo info, 
        StreamingContext context) {

        base.GetObjectData(info, context);
        info.AddValue("ErrorCode", ErrorCode);
    }

    #endregion
}

private void button1_Click(object sender, EventArgs e) {
    MyException ex = new MyException("Hello, world!");
    ex.ErrorCode = 20;
    WrappedException reply = new WrappedException(ex);
    XmlSerializer x = new XmlSerializer(reply.GetType());
    MemoryStream stream = new MemoryStream();
    x.Serialize(stream, reply);
    stream.Position = 0;
    WrappedException reply2 = (WrappedException)x.Deserialize(stream);
    MyException ex2 = (MyException)reply2.GetException();
    stream.Close();
    Text = ex2.ErrorCode.ToString(); // form shows 20

    // throw ex2;

    }

Хотя казалось, что все другие типы исключений, которые я искал, отмечены атрибутом SerializableAttribute, мне придется быть осторожным с настраиваемыми исключениями, которые не отмечены атрибутом SerializableAttribute.

Обновлено: забегая вперед. Я не понимал, что BinaryFormatter не реализован на CF.

Обновлено: приведенные выше фрагменты кода были в настольном проекте. В версии CF WrappedException будет в основном выглядеть так же, как и просто, необходимый для реализации моего собственного BinaryFormater, но я очень открыт для предложений по этому поводу.

Что ж, сериализация XML ограничена в использовании. Например, он не может сериализовать этот конкретный сценарий. Для точной сериализации и десериализации исключений вам нужно будет использовать BinaryFormatter, который будет работать, пока ваши собственные исключения помечены как [Serializable]. Все исключения .Net помечены этим SerializableAttribute, что означает, что они могут быть сериализованы с помощью BinaryFormatter.

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

Если исключения .NET помечены [Serializable], почему они не сериализуются с помощью TextFormatter? Или, по крайней мере, почему фреймворк с ними справляется, когда передает их браузеру, когда вы отлаживаете веб-сервис?

nicodemus13 20.01.2009 22:27

Я не знаю, что такое TextFormatter, поэтому я не могу на это ответить. Однако, насколько мне известно, SerializableAttribute используется только в двоичной сериализации. Кроме того, если исключение имеет поле объекта, и это поле содержит несериализуемые данные, сериализация завершится ошибкой.

configurator 25.01.2009 19:52

[...] Что тогда будет делать фреймворк при отладке веб-службы?

configurator 25.01.2009 19:53

Я следовал методу, предложенному в этом ссылка на сайт (прокрутите вниз, чтобы найти ответ, опубликованный человеком по имени Кубилай), и он отлично работает для меня. Нет необходимости создавать какие-либо классы-оболочки для объекта исключения.

Через год я снова нашел свой собственный ответ полезным.

muruge 27.08.2012 20:02

Используете NetDataContractSerializer?

Kiquenet 13.03.2018 12:08

Другие вопросы по теме