Obteniendo System.Net.Mail.MailMessage como un MemoryStream en .NET 4.5 beta

Por lo tanto, el código siguiente solía funcionar en .NET 4 para obtener un objeto System.Net.Mail.MailMessage como un MemoryStream, sin embargo, con el lanzamiento de .NET 4.5 beta se produce una excepción de tiempo de ejecución.

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

La excepción de tiempo de ejecución se produce en sendMethod.Invoke ().

Logré averiguar cómo hacer que esto vuelva a funcionar en .NET 4.5 beta. El método privado API Send () en MailMessage ha cambiado a: interno void Send (escritor BaseWriter, bool sendEnvelope, bool allowUnicode)

Por favor, encuentre el código actualizado a continuación.

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

Esto podría ser útil si no quieres ir con hacks no compatibles y no te molesta el rendimiento extra.

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

para verificar si utilizo booleanos extra:

  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 

La solución propuesta con el TRUE extra funciona maravillosamente.

Comencé a obtener el error al ejecutar mi proyecto en VS2012 aunque no estoy usando .NET 4.5 pero 4.0 en todas mis bibliotecas.

El error solo ocurre en la máquina donde instaló VS2012, parece que VS2012 hace referencia a .NET 4.5 mientras está depurando. Cuando implementa y ejecuta la aplicación en clientes que ejecutan .net 4.0 todo funciona bien.

Por lo tanto: si ejecuta 4.0, no agregue el valor TRUE extra, si ejecuta 4.5, agréguelo.