Я хочу записать исключение в очередь сообщений 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();
Обновлено: Я старался сделать это как можно проще, но, возможно, переборщил. Мне нужен весь бит, трассировка стека, сообщение, настраиваемый тип исключения и настраиваемые свойства исключения. Возможно, я даже захочу снова выбросить исключение.





Почему? Вы создаете экземпляр исключения при его извлечении из очереди сообщений? Если нет, просто отправьте сообщение об исключении (в виде строки) ...
> Вы создаете экземпляр исключения при его извлечении из очереди сообщений? Да.
Вы не можете сериализовать словарь в xml. Сделайте то, что сказал другой парень, и отправьте сообщение, это в любом случае важный момент.
Я думаю, у вас в основном есть два варианта:
Сериализация исключений - это обычная задача при удаленном взаимодействии с системами через границы процессов. Не слушайте никого, кто говорит иначе; они, вероятно, никогда не писали удаленную библиотеку.
Для этого я уже использовал удаленное взаимодействие, создав собственный базовый класс исключений. Проблема, с которой я столкнулся, заключалась в том, что 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? Или, по крайней мере, почему фреймворк с ними справляется, когда передает их браузеру, когда вы отлаживаете веб-сервис?
Я не знаю, что такое TextFormatter, поэтому я не могу на это ответить. Однако, насколько мне известно, SerializableAttribute используется только в двоичной сериализации. Кроме того, если исключение имеет поле объекта, и это поле содержит несериализуемые данные, сериализация завершится ошибкой.
[...] Что тогда будет делать фреймворк при отладке веб-службы?
Я следовал методу, предложенному в этом ссылка на сайт (прокрутите вниз, чтобы найти ответ, опубликованный человеком по имени Кубилай), и он отлично работает для меня. Нет необходимости создавать какие-либо классы-оболочки для объекта исключения.
Через год я снова нашел свой собственный ответ полезным.
Используете NetDataContractSerializer?
Или, что еще лучше, отправьте свойство StackTrace в виде строки