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

时间:2012-03-07 03:35:46

标签: c# .net-4.5

因此,下面的代码曾经在.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);

    .....
}

sendMethod.Invoke()上发生运行时异常。

5 个答案:

答案 0 :(得分:30)

管理如何在.NET 4.5 beta中重新使用它。 MailMessage中的私有API Send()方法已更改为:internal void Send(BaseWriter writer,bool sendEnvelope,bool allowUnicode)

请在下面找到更新的代码。

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);

    .....
}

答案 1 :(得分:12)

如果您不想使用不受支持的黑客并且不介意额外的性能影响,这可能是有用的。

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 );
        }
    }

答案 2 :(得分:9)

用于检查我是否使用了额外的布尔值:

 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

答案 3 :(得分:0)

带有额外TRUE的建议解决方案非常有效。

我在VS2012中运行项目时遇到错误,即使我在所有库中都没有使用.net 4.5但是4.0。

错误只发生在安装了VS2012的机器上,看起来VS2012在调试时会引用.net 4.5。在运行.net 4.0的客户端中部署和运行应用程序时,一切正常。

因此:如果你运行4.0 - 不要添加额外的TRUE,如果你运行4.5添加它。

答案 4 :(得分:0)

我们与邮件转换进行了长期的战斗。最终,解决方案是使用MimeKit

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

如果您使用上述方法,您将会非常接近,并且在大多数文化中都可以使用,但是最终主题编码会打败您。