2012-03-07 14 views
21

Quindi, il codice seguente utilizzato per funzionare in. NET 4 per ottenere un oggetto System.Net.Mail.MailMessage come MemoryStream, tuttavia con la versione di .NET 4.5 beta si verifica un'eccezione di runtime.Ottenere System.Net.Mail.MailMessage come MemoryStream in .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); 

    ..... 
} 

eccezione di runtime si verifica su sendMethod.Invoke().

+0

Qual è l'eccezione (stack trace può aiutare)? –

+0

Eccezione: System.Reflection.TargetParameterCountException: mancata corrispondenza del conteggio dei parametri. – dimoss

+0

Hai confrontato il codice .NET 4 in .NET 4.5 per vedere se hanno eliminato un sovraccarico di "Invia"? Questo potrebbe certamente essere gestito più semplicemente con l'uso di 'dinamico'. –

risposta

29

Gestito per capire come riavviare il funzionamento in. NET 4.5 beta. Il metodo Send() API privato in MailMessage è stato modificato in: internal void Send (autore BaseWriter, bool sendEnvelope, bool allowUnicode)

Si prega di trovare il codice aggiornato di seguito.

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

Ecco cosa si ottiene per l'accesso a metodi non pubblici :) –

+7

Per quanto ho potuto indagare, non c'è altro modo per ottenere il MemoryStream di un messaggio di posta. Anche i post precedenti qui utilizzano il metodo API privato e persino gli esempi dei fornitori di terze parti utilizzano questo metodo API privato. Se qualcuno conosce un modo per farlo utilizzando le API pubbliche, sarebbe di grande aiuto condividerla :) – dimoss

+0

Ciao, ho lo stesso problema ma per closeMethod.Invoke (mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object [] {}, null); ... qualche indizio? Grazie – VAAA

0

La soluzione proposta con l'extra TRUE funziona magnificamente.

Ho iniziato a ricevere l'errore durante l'esecuzione del mio progetto in VS2012 anche se non sto utilizzando .net 4.5 ma 4.0 in tutte le mie librerie.

L'errore si verifica solo sulla macchina su cui è installato VS2012, sembra che VS2012 faccia riferimento a .net 4.5 durante il debug. Quando si distribuisce e si esegue l'applicazione nei client che eseguono .net 4.0, tutto funziona correttamente.

Così: Se si esegue 4.0 - non aggiungere il VERO extra, se si esegue 4.5 aggiungerlo.

+0

Sì, mi sono imbattuto anche in questo. Ho dovuto inserire condizionali del compilatore in modo da poter eseguire il debug del codice e farlo funzionare in produzione. – efbenson

12

Questo potrebbe essere utilizzabile se non si desidera eseguire gli hack non supportati e non si deve preoccupare di un impatto sulle prestazioni 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); 
     } 
    } 
+0

Un bel workaround, e probabile che funzioni attraverso ulteriori versioni di API. Grazie! – antlersoft

9

per verificare se booleano aggiuntivo che uso:

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

Questo ha funzionato per me con .NET 4.0 e 4.5. Grazie! – LuckyStrike

Problemi correlati