2012-03-07 23 views
21

Vì vậy, đoạn mã dưới đây được sử dụng để làm việc trong .NET 4 để có được một đối tượng System.Net.Mail.MailMessage như là một MemoryStream, tuy nhiên với bản phát hành của .NET 4.5 beta một ngoại lệ thời gian chạy xảy ra.Lấy System.Net.Mail.MailMessage làm một MemoryStream trong .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); 

    ..... 
} 

Ngoại lệ thời gian chạy xảy ra trên sendMethod.Invoke().

+0

trừ (stack trace có thể giúp) là gì? –

+0

Ngoại lệ là: System.Reflection.TargetParameterCountException: Số tham số không khớp. – dimoss

+0

Bạn đã so sánh mã .NET 4 với .NET 4.5 để xem liệu chúng có giảm quá tải 'Gửi' không? Điều này chắc chắn có thể được xử lý đơn giản hơn với việc sử dụng 'dynamic'. –

Trả lời

29

Được quản lý để tìm ra cách làm việc này một lần nữa trong .NET 4.5 beta. Phương thức Send() API riêng trong MailMessage đã thay đổi thành: internal void Send (Trình soạn thảo BaseWriter, bool sendEnvelope, bool allowUnicode)

Vui lòng tìm mã được cập nhật bên dưới.

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

    ..... 
} 
+0

Đó là những gì bạn nhận được để truy cập các phương pháp phi công cộng :) –

+7

Theo như tôi có thể điều tra, không có cách nào khác để lấy MemoryStream của MailMessage. Ngay cả các bài đăng trước đây trên đây đều sử dụng phương pháp API riêng tư và thậm chí các ví dụ từ các nhà cung cấp bên thứ ba cũng sử dụng phương pháp API riêng tư này. Nếu bất cứ ai biết về một cách để làm điều này bằng cách sử dụng API công cộng nó sẽ là một trợ giúp lớn để chia sẻ nó :) – dimoss

+0

Hi, Im có cùng một vấn đề nhưng đối với closeMethod.Invoke (mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new đối tượng [] {}, null); ... bất kỳ đầu mối nào? Cảm ơn – VAAA

0

Giải pháp được đề xuất có thêm TRUE hoạt động đẹp mắt.

Tôi bắt đầu gặp lỗi khi chạy dự án của mình trong VS2012 mặc dù tôi không sử dụng .net 4.5 nhưng 4.0 trong tất cả các thư viện của tôi.

Lỗi chỉ xảy ra trên máy nơi bạn đã cài đặt VS2012, có vẻ như VS2012 tham chiếu đến .net 4.5 trong khi bạn đang gỡ lỗi. Khi bạn triển khai và chạy ứng dụng trong các máy khách đang chạy .net 4.0 mọi thứ hoạt động tốt.

Do đó: Nếu bạn chạy 4.0 - không thêm TRUE phụ, nếu bạn chạy 4.5, hãy thêm nó.

+0

Vâng, tôi cũng đã tham gia trò chơi này. Đã phải đặt điều kiện trình biên dịch để chúng tôi có thể gỡ lỗi mã và có nó hoạt động trong sản xuất. – efbenson

12

Điều này có thể sử dụng được nếu bạn không muốn sử dụng các phần mềm không được hỗ trợ và không để ý đến hiệu suất phụ.

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

Giải pháp tốt và có khả năng hoạt động thông qua các phiên bản api khác. Cảm ơn! – antlersoft

9

để kiểm tra nếu thêm boolean tôi sử dụng:

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 
+1

Điều này làm việc cho tôi với .NET 4.0 và 4.5. Cảm ơn! – LuckyStrike

Các vấn đề liên quan