问题
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.
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.
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.
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.
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.
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...
Any pointers as to how I could make this more elegant will be much appreciated.
Thanks.
回答1:
This will be a hack. Don't forget, MS can change it in the next versions of .Net.
(With the help of ILSpy) you can write an extension method like below
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();
回答2:
I finally managed to deserialize the MailMessage after a lot of work:
To get it right, I created a dll which will be used in both the client application and the webservice. 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
Many thanks for sharing!
Once compiled and added my new dll to the projects, the send and receive worked.
So I convert the MailMessage this way : string serializedMessage = SerializeAsBase64(mail); and in the Webservice, I reconstruct it this way : MailMessage Mm = DeserializeFromBase64(serializedMessage);
I hope this helps...
来源:https://stackoverflow.com/questions/18745392/elegant-way-to-serialize-a-mailmessage-object-in-net