简体   繁体   English

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

[英]Elegant way to serialize a MailMessage object in .NET

I'm currently looking at serializing a MailMessage object in C# and although there are a couple of variations of an example on the net, they serialize to binary which kind of misses the point IMO. 我目前正在考虑在C#中序列化一个MailMessage对象,虽然网上有一些示例的变体,但它们会序列化为二进制,这种点错过了IMO点。

My approach is that I'd like to serialize a MailMessage to an RFC2822 eml string and the code below is what I've come up with. 我的方法是,我想将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;
    }

It's pretty nasty but it does work. 它非常讨厌,但确实有效。 Ideally though, I'd create a new SMTPClient and add in a Serialize function which would return the rfc822 string automatically without it ever hitting the file system. 理想情况下,我会创建一个新的SMTPClient并添加一个Serialize函数,该函数将自动返回rfc822字符串,而不会访问文件系统。

As I don't seem to be able to trace into the SMTPClient.Send function with Visual Studio, this "ideal" way of doing things is a tad tricky. 由于我似乎无法使用Visual Studio跟踪SMTPClient.Send函数,因此这种“理想”的处理方式有点棘手。

I've already sorted out the deserialization of the RFC message by adding in some small changes to Peter Huber's POP3MimeClient and POP3MailClient classes so I can deserialize a file on the HDD or a string back into a MailMessage. 我已经通过在Peter Huber的POP3MimeClient和POP3MailClient类中添加一些小的更改来整理RFC消息的反序列化,这样我就可以将HDD上的文件或字符串反序列化为MailMessage。

The thing that's nagging at me is that I really should be able to serialize the MailMessaage using a stream and writing the stream to a string -or- file of my choice instead of going around the houses to create GUID based folders as the code above does and reading the content of the file back into a string... 对我唠叨的是,我真的应该能够使用流序列化MailMessaage并将流写入我选择的字符串 - 或 - 文件而不是绕过房子创建基于GUID的文件夹,如上面的代码所做的那样并将文件内容读回字符串...

Any pointers as to how I could make this more elegant will be much appreciated. 关于如何使这更优雅的任何指示将非常感激。

Thanks. 谢谢。

This will be a hack. 这将是一个黑客。 Don't forget, MS can change it in the next versions of .Net. 不要忘记,MS可以在.Net的下一个版本中进行更改。

(With the help of ILSpy) you can write an extension method like below (在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());
    }
}

and use as 并用作

string eml = mailMessage.ToEml();

I finally managed to deserialize the MailMessage after a lot of work: 经过大量工作后,我终于设法对MailMessage进行反序列化:

To get it right, I created a dll which will be used in both the client application and the webservice. 为了做到这一点,我创建了一个将在客户端应用程序和Web服务中使用的DLL。 This needs to be the same for the deserialization to work :) 这需要相同的反序列化工作:)

I picked the dll serialization classes here: https://bitbucket.org/burningice/compositec1contrib.email/src/0bba07df532c8134717cfb40757f4cb22f002b1d/Email/Serialization/?at=default 我在这里选择了dll序列化类: https//bitbucket.org/burningice/compositec1contrib.email/src/0bba07df532c8134717cfb40757f4cb22f002b1d/Email/Serialization/?at=default

Many thanks for sharing! 非常感谢分享!

Once compiled and added my new dll to the projects, the send and receive worked. 编译完成后,将我的新dll添加到项目中,发送和接收工作正常。

So I convert the MailMessage this way : string serializedMessage = SerializeAsBase64(mail); 所以我用这种方式转换MailMessage:string serializedMessage = SerializeAsBase64(mail); and in the Webservice, I reconstruct it this way : MailMessage Mm = DeserializeFromBase64(serializedMessage); 在Webservice中,我用这种方式重建它:MailMessage Mm = DeserializeFromBase64(serializedMessage);

I hope this helps... 我希望这有帮助...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM