Как упорядочить почтовое сообщение?
Я получаю следующее при привязке к сериализации сообщения с использованием los foratter.
Ошибка: Sys.WebForms.PageRequestManagerServerErrorException: Ошибка сериализации значения "System.Net.Mail.MailMessage" типа "System.Net.Mail.MailMessage."
Есть ли простой способ сериализации этого объекта, или мне нужно каждый раз обследовать каждый из свойств fhte?
Ответы
Ответ 1
К сожалению, класс System.Net.Mail.MailMessage не помечен как сериализуемый. Итак, да, вам нужно будет сделать это самостоятельно. Там описан способ, описанный в следующем блоге, который может дать вам представление о том, как вы можете продолжить: Как сериализовать MailMessage... в основном, вам нужно будет вытащить каждый из свойств по отдельности. Цитата:
Чтобы сериализовать свойства объекта MailMessage, вы можете создать новый класс и создать свойство типа MailMessage для него, которое внедряет ваш MailMessage в классе. В этом новом классе вы можете реализовать IXmlSerializable интерфейс для ручного сериализации его MailMessage. Вот Я создаю этот класс и называю его SerializableMailMessage [...]
[реализация кода методов WriteXml() и ReadXml(); см. ссылку источника]
Ответ 2
Для тех, кто ищет полный исходный код , как сериализовать MailMessage в XML, написанный Keyvan Nayyeri, вот ссылка на его github:
https://github.com/keyvan/Gopi/blob/master/Gopi/Gopi/SerializableMailMessage.cs
И вот архив его блога, который теперь не функционирует:
http://web.archive.org/web/20131124074822/http://keyvan.io/how-to-serialize-a-mailmessage
На всякий случай вышеприведенная ссылка тоже может стать мертвой, здесь я снова разместил свой блог здесь:
Сериализация MailMessage
В .NET есть два класса MailMessage. Первый из них находится в пространстве имен System.Web.Mail и устарел в .NET 2.0 и более поздних версиях, а второй доступен в System.Net.Mail. Я не забочусь об устаревших, поэтому просто покажу, как вы можете сериализовывать экземпляры класса System.Net.Mail.MailMessage.
Чтобы сериализовать свойства объекта MailMessage, вы можете создать новый класс и создать для него свойство типа MailMessage, которое введет ваш MailMessage в класс. В этом новом классе вы можете реализовать интерфейс IXmlSerializable, чтобы вручную сериализовать его MailMessage.
Сериализация
Сериализация стороны выполняется так же просто, как реализация метода WriteXml. Ниже приведен код, который я написал для этого.
public void WriteXml(XmlWriter writer)
{
if (this != null)
{
writer.WriteStartElement("MailMessage");
writer.WriteAttributeString("Priority", Convert.ToInt16(this.Priority).ToString());
writer.WriteAttributeString("IsBodyHtml", this.IsBodyHtml.ToString());
// From
writer.WriteStartElement("From");
if (!string.IsNullOrEmpty(this.From.DisplayName))
writer.WriteAttributeString("DisplayName", this.From.DisplayName);
writer.WriteRaw(this.From.Address);
writer.WriteEndElement();
// To
writer.WriteStartElement("To");
writer.WriteStartElement("Addresses");
foreach (MailAddress address in this.To)
{
writer.WriteStartElement("Address");
if (!string.IsNullOrEmpty(address.DisplayName))
writer.WriteAttributeString("DisplayName", address.DisplayName);
writer.WriteRaw(address.Address);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndElement();
// CC
if (this.CC.Count > 0)
{
writer.WriteStartElement("CC");
writer.WriteStartElement("Addresses");
foreach (MailAddress address in this.CC)
{
writer.WriteStartElement("Address");
if (!string.IsNullOrEmpty(address.DisplayName))
writer.WriteAttributeString("DisplayName", address.DisplayName);
writer.WriteRaw(address.Address);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndElement();
}
// Bcc
if (this.Bcc.Count > 0)
{
writer.WriteStartElement("Bcc");
writer.WriteStartElement("Addresses");
foreach (MailAddress address in this.Bcc)
{
writer.WriteStartElement("Address");
if (!string.IsNullOrEmpty(address.DisplayName))
writer.WriteAttributeString("DisplayName", address.DisplayName);
writer.WriteRaw(address.Address);
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndElement();
}
// Subject
writer.WriteStartElement("Subject");
writer.WriteRaw(this.Subject);
writer.WriteEndElement();
// Body
writer.WriteStartElement("Body");
writer.WriteCData(Body);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
После такого же подхода вы можете сериализовать другие свойства, такие как вложения. На следующей неделе я выпущу новую версию Gopi, которая содержит обновленный код, который сериализует все, чтобы вы могли скоро подождать, чтобы получить код.
Десериализация
public void ReadXml(XmlReader reader)
{
XmlDocument xml = new XmlDocument();
xml.Load(reader);
// Properties
XmlNode rootNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage");
this.IsBodyHtml = Convert.ToBoolean(rootNode.Attributes["IsBodyHtml"].Value);
this.Priority = (MailPriority)Convert.ToInt16(rootNode.Attributes["Priority"].Value);
// From
XmlNode fromNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/From");
string fromDisplayName = string.Empty;
if (fromNode.Attributes["DisplayName"] != null)
fromDisplayName = fromNode.Attributes["DisplayName"].Value;
MailAddress fromAddress = new MailAddress(fromNode.InnerText, fromDisplayName);
this.From = fromAddress;
// To
XmlNode toNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/To/Addresses");
foreach (XmlNode node in toNode.ChildNodes)
{
string toDisplayName = string.Empty;
if (node.Attributes["DisplayName"] != null)
toDisplayName = node.Attributes["DisplayName"].Value;
MailAddress toAddress = new MailAddress(node.InnerText, toDisplayName);
this.To.Add(toAddress);
}
// CC
XmlNode ccNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/CC/Addresses");
foreach (XmlNode node in ccNode.ChildNodes)
{
string ccDisplayName = string.Empty;
if (node.Attributes["DisplayName"] != null)
ccDisplayName = node.Attributes["DisplayName"].Value;
MailAddress ccAddress = new MailAddress(node.InnerText, ccDisplayName);
this.CC.Add(ccAddress);
}
// Bcc
XmlNode bccNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/Bcc/Addresses");
foreach (XmlNode node in bccNode.ChildNodes)
{
string bccDisplayName = string.Empty;
if (node.Attributes["DisplayName"] != null)
bccDisplayName = node.Attributes["DisplayName"].Value;
MailAddress bccAddress = new MailAddress(node.InnerText, bccDisplayName);
this.Bcc.Add(bccAddress);
}
// Subject
XmlNode subjectNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/Subject");
this.Subject = subjectNode.InnerText;
// Body
XmlNode bodyNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/Body");
this.Body = bodyNode.InnerText;
}
Над кодом используется вспомогательный метод для получения XmlNode для разных разделов.
public XmlNode GetConfigSection(XmlDocument xml, string nodePath)
{
return xml.SelectSingleNode(nodePath);
}
Этот код не требует пояснений и не нуждается в комментариях, но обратите внимание, что вам нужно обновить выражения XPath для ваших имен классов. Конечно, я мог бы использовать отражение, чтобы сделать этот код более общим, но иногда я плохой парень.
Ответ 3
Я знаю, что это более старая запись, но у меня также была проблема, когда мне нужно было сериализовать класс MailAddress, поэтому я создал сериализуемую версию. Если вы в состоянии использовать собственный класс MailAddress вместо класса System.Net.Mail.MailAddress, это может сработать для вас.
/// <summary>
/// Serializable implementation of <see cref="System.Net.Mail.MailAddress"/>.
/// </summary>
[Serializable]
public class MailAddress : System.Net.Mail.MailAddress, ISerializable
{
// Keep reference to the display name encoding so we can serialize/deserialize the value
private readonly Encoding _displayNameEncoding;
public MailAddress(string address)
: this(address, null, null)
{
}
public MailAddress(string address, string displayName)
: this(address, displayName, null)
{
}
public MailAddress(string address, string displayName, Encoding displayNameEncoding)
: base(address, displayName, displayNameEncoding)
{
// Keep reference to the supplied displayNameEncoding so we can serialize/deserialize this value
_displayNameEncoding = displayNameEncoding ?? Encoding.GetEncoding("utf-8");
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Address", base.Address);
info.AddValue("DisplayName", base.DisplayName);
info.AddValue("DisplayNameEncoding", _displayNameEncoding);
}
protected MailAddress(SerializationInfo info, StreamingContext context)
: this(info.GetString("Address"), info.GetString("DisplayName"), (Encoding)info.GetValue("DisplayNameEncoding", typeof (Encoding)))
{
}
}