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

В С#, как я могу сериализовать System.Exception? (.Net CF 2.0)

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

{ "Произошла ошибка, отражающая тип 'System.Exception'." }

с InnerException:

{ "Невозможно выполнить сериализацию элемента System.Exception.Data типа System.Collections.IDictionary, потому что он реализует 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();

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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.

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

Ответ 3

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

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

Решение:

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

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

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

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

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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