简体   繁体   English

在 .NET 4.5 beta 中将 System.Net.Mail.MailMessage 作为 MemoryStream

[英]Getting System.Net.Mail.MailMessage as a MemoryStream in .NET 4.5 beta

So, the below code used to work in .NET 4 to get a System.Net.Mail.MailMessage object as a MemoryStream, however with the release of .NET 4.5 beta a runtime exception occurs.因此,下面的代码用于在 .NET 4 中工作以获取 System.Net.Mail.MailMessage 对象作为 MemoryStream,但是随着 .NET 4.5 beta 的发布,会发生运行时异常。

Assembly assembly = typeof(SmtpClient).Assembly;
Type mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
using (MemoryStream stream = new MemoryStream())
{
    ConstructorInfo mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
    object mailWriter = mailWriterContructor.Invoke(new object[] { stream });
    MethodInfo sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
    sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true }, null);

    .....
}

Runtime exception occurs on sendMethod.Invoke(). sendMethod.Invoke() 上发生运行时异常。

Managed to figure out how to get this working again in .NET 4.5 beta. 设法弄清楚如何在.NET 4.5 beta中再次使它工作。 The private API Send() method in MailMessage has changed to: internal void Send(BaseWriter writer, bool sendEnvelope, bool allowUnicode) MailMessage中的私有API Send()方法已更改为:内部void Send(BaseWriter writer,bool sendEnvelope,bool allowUnicode)

Please find updated code below. 请在下面找到更新的代码。

Assembly assembly = typeof(SmtpClient).Assembly;
Type mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
using (MemoryStream stream = new MemoryStream())
{
    ConstructorInfo mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
    object mailWriter = mailWriterContructor.Invoke(new object[] { stream });
    MethodInfo sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
    sendMethod.Invoke(message, BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { mailWriter, true, true }, null);

    .....
}

This might be usable if you don't want to go with unsupported hacks and don't mind extra performance hit. 如果您不想使用不受支持的骇客并且不介意额外的性能损失,这可能会有用。

public static class MailMessageExtensions
    {
    public static string  RawMessage(this MailMessage m)
        {
        var smtpClient = new SmtpClient { DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory };

        using (var tempDir = new TemporaryDirectory())
            {
            smtpClient.PickupDirectoryLocation = tempDir.DirectoryPath;
            smtpClient.Send( m );
            var emlFile = Directory.GetFiles( smtpClient.PickupDirectoryLocation ).FirstOrDefault();
            if ( emlFile != null )
                {
                return File.ReadAllText( emlFile );
                }
            else
                return null;
            }
        return null;
        }

    }

class TemporaryDirectory : IDisposable
    {
    public TemporaryDirectory()
        {
        DirectoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
        Directory.CreateDirectory( DirectoryPath );
        }

    public string DirectoryPath { get; private set; }

    public void Dispose()
        {
        if ( Directory.Exists( DirectoryPath ) )
            Directory.Delete( DirectoryPath, true );
        }
    }

for checking if extra boolean i use : 用于检查是否使用了额外的布尔值:

 If _sendMethod.GetParameters.Length = 2 Then
    _sendMethod.Invoke(Message, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Object() {_mailWriter, True}, Nothing)
 Else
    _sendMethod.Invoke(Message, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Object() {_mailWriter, True, True}, Nothing)
 End If

The proposed solution with the extra TRUE works beautifully. 带有TRUE的建议解决方案效果很好。

I started to getting the error while running my project in VS2012 even though I am not using .net 4.5 but 4.0 in all my libraries. 我在VS2012中运行项目时开始出现错误,即使我在所有库中都不使用.net 4.5而是4.0。

The error only happens on the machine where you have installed VS2012, looks like VS2012 makes reference to .net 4.5 while you are debugging. 该错误仅发生在安装了VS2012的计算机上,好像VS2012在调试时参考了.net 4.5。 When you deploy and run the application in clients running .net 4.0 everything works fine. 在运行.net 4.0的客户端中部署和运行应用程序时,一切正常。

Thus : If you run 4.0 - do not add the extra TRUE, if you run 4.5 add it. 因此:如果您运行4.0-不要添加额外的TRUE,如果您运行4.5,则添加它。

We fought with the mail message conversion for a long time. 我们与邮件转换进行了很长时间的斗争。 Ultimately the solution was to use MimeKit . 最终,解决方案是使用MimeKit

var memoryStream = new MemoryStream();
var mimeMessage = MimeMessage.CreateFromMailMessage(message);
mimeMessage.WriteTo(memoryStream);

If you use the methods above you will get really close and it will work in most cultures but eventually the subject encoding will defeat you. 如果您使用上面的方法,您会非常接近,并且在大多数文化中都可以使用,但是最终主题编码将使您败北。

For those, who are struggling with mailWriterContructor being null in .NET 5 or facing Parameter count mismatch exception, take a closer look on my solution usable for any stream.对于那些在.NET 5 中null mailWriterContructor或面临参数计数不匹配异常而苦苦挣扎的人,请仔细查看我的可用于任何流的解决方案。 Link here链接在这里

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

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