Получение System.Net.Mail.MailMessage как MemoryStream в .NET 4.5 beta
Итак, приведенный ниже код использовался для работы в .NET 4, чтобы получить объект System.Net.Mail.MailMessage как MemoryStream, однако с выпуском бета-версии .NET 4.5 возникает исключение среды выполнения.
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().
Ответы
Ответ 1
Удалось выяснить, как это сделать снова в бета-версии .NET 4.5. Частный API-метод Send() в MailMessage изменился на: internal void Send (создатель BaseWriter, 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);
.....
}
Ответ 2
Это может быть полезно, если вы не хотите идти с неподдерживаемыми хаками и не возражаете против увеличения производительности.
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 );
}
}
Ответ 3
для проверки использования дополнительного логического значения:
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
Ответ 4
Предлагаемое решение с дополнительным TRUE работает красиво.
Я начал получать ошибку при запуске моего проекта в VS2012, хотя я не использую .net 4.5, но 4.0 во всех моих библиотеках.
Ошибка происходит только на компьютере, на котором установлена VS2012, выглядит так: VS2012 ссылается на .net 4.5 во время отладки. Когда вы развертываете и запускаете приложение в клиентах, работающих с .net 4.0, все работает нормально.
Таким образом: если вы запустите 4.0 - не добавляйте дополнительный TRUE, если вы запустите 4.5, добавьте его.
Ответ 5
Мы долго боролись с конверсией почтовых сообщений. В конечном итоге решение было использовать MimeKit.
var memoryStream = new MemoryStream();
var mimeMessage = MimeMessage.CreateFromMailMessage(message);
mimeMessage.WriteTo(memoryStream);
Если вы воспользуетесь описанными выше методами, вы очень близко подойдете, и это сработает в большинстве культур, но в конечном итоге кодировка объекта победит вас.