C# 在.NET中序列化MailMessage对象的优雅方法

C# 在.NET中序列化MailMessage对象的优雅方法,c#,serialization,mailmessage,rfc822,rfc2822,C#,Serialization,Mailmessage,Rfc822,Rfc2822,我目前正在考虑在C#中序列化一个MailMessage对象,尽管网络上有几个示例的变体,但它们序列化为二进制,这在某种程度上忽略了要点 我的方法是将邮件消息序列化为RFC2822 eml字符串,下面的代码就是我想到的 public string SerializeEmail(MailMessageArgs e) { string rfc822eml = ""; Guid g = Guid.NewGuid(); lock (g.ToS

我目前正在考虑在C#中序列化一个MailMessage对象,尽管网络上有几个示例的变体,但它们序列化为二进制,这在某种程度上忽略了要点

我的方法是将邮件消息序列化为RFC2822 eml字符串,下面的代码就是我想到的

    public string SerializeEmail(MailMessageArgs e)
    {
        string rfc822eml = "";
        Guid g = Guid.NewGuid();
        lock (g.ToString())
        {
            System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(@"C:\tmpspool");
            di.CreateSubdirectory(g.ToString());
            string spoolDir = @"C:\tmpspool\" + g.ToString();
            SmtpClient Client = new SmtpClient("localhost");
            Client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
            Client.PickupDirectoryLocation = spoolDir;
            Client.Send(e.mailObj);
            var files = from file in Directory.EnumerateFiles(spoolDir)
                       select file;
            string serializedEml = files.First();
            rfc822eml = File.ReadAllText(serializedEml);
            File.Delete(serializedEml);
            Directory.Delete(spoolDir);
        }

        return rfc822eml;
    }
这很恶心,但确实管用。理想情况下,我会创建一个新的SMTPClient并添加一个序列化函数,该函数将自动返回rfc822字符串,而不会影响文件系统

由于我似乎无法跟踪到VisualStudio的SMTPClient.Send函数,这种“理想”的处理方式有点棘手

我已经通过对Peter Huber的POP3MimeClient和POP3MailClient类添加一些小更改来整理RFC消息的反序列化,这样我就可以将硬盘上的文件或字符串反序列化回MailMessage

困扰我的是,我真的应该能够使用流序列化MailMessaage,并将流写入我选择的字符串或文件,而不是像上面的代码那样到处创建基于GUID的文件夹,并将文件内容读回字符串

任何关于我如何使这更优雅的建议都将不胜感激

谢谢。

这将是一次黑客攻击。别忘了,微软可以在下一个版本的.Net中更改它

(在ILSpy的帮助下)您可以编写如下的扩展方法

public static class MailExtensions
{
    public static string ToEml(this MailMessage mail)
    {
        var stream = new MemoryStream();
        var mailWriterType = mail.GetType().Assembly.GetType("System.Net.Mail.MailWriter");
        var mailWriter = Activator.CreateInstance(
                            type: mailWriterType,
                            bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic,
                            binder: null,
                            args: new object[] { stream },
                            culture: null,
                            activationAttributes: null);

        mail.GetType().InvokeMember(
                            name: "Send",
                            invokeAttr: BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
                            binder: null,
                            target: mail,
                            args: new object[] { mailWriter, true, true });


        return Encoding.UTF8.GetString(stream.ToArray());
    }
}
并用作

string eml = mailMessage.ToEml();

经过大量工作,我终于成功地反序列化了邮件消息:

为了使它正确,我创建了一个dll,它将在客户端应用程序和Web服务中使用。这需要与反序列化工作相同:)

我在这里选择了dll序列化类:

非常感谢分享

一旦编译并将我的新dll添加到项目中,发送和接收就可以工作了

因此,我将邮件消息转换为:string serializedMessage=SerializeAsBase64(邮件); 在Web服务中,我以这种方式重建它: MailMessage Mm=反序列化FromBase64(serializedMessage)


我希望这有助于

谢谢你。我对它做了一些微调,以处理我们定制的MailMessage对象,它有一些额外的特性,结果令人印象深刻。它工作完美,速度快,优雅,正如我所认为的那样。非常酷:为什么他们不公开API!我的沉默,现在删除评论。这是一个非常好的扩展。是否有人实现了EML back to MailMessage?使用POP客户端并重写一两个函数来获取流并将其加载到MailMessage中。RFC2822格式与通过POP和IMAP客户端提供的格式相同,因此您应该能够非常轻松地对其进行反序列化。您好@PaulV-您介意共享反序列化位吗?非常感谢。嗨,这不容易分享。当时我正在起草一份合同,我再也不能使用该代码了。如果我没记错的话,它基本上是将字符串从DB加载到流中,然后从那里填充消息对象,就像您从流上的POP服务器下载它一样。