2012-03-07 13 views
21

したがって、以下のコードは.NET 4でSystem.Net.Mail.MailMessageオブジェクトをMemoryStreamとして取得するために使用されていましたが、 .NET 4.5ベータ版では実行時例外が発生します。System.Net.Mail.MailMessageを.NET 4.5ベータ版のMemoryStreamとして取得

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()で発生します。

+0

は、(スタックトレースが役立つかもしれない)例外は何ですか? –

+0

例外は次のとおりです。 System.Reflection.TargetParameterCountException:パラメーターの数が一致しません。 – dimoss

+0

.NET 4のコードを.NET 4.5と比較して、それらが 'Send'のオーバーロードを落としたかどうかを確認しましたか?これは、「ダイナミック」を使用することで、より簡単に処理できます。 –

答えて

29

.NET 4.5ベータ版でこの問題を再現する方法を把握することができました。 MailMessageのプライベートAPI Send()メソッドが次のように変更されました: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); 

    ..... 
} 
+0

それはあなたが非公開のメソッドにアクセスするために得られるものです。 –

+7

私が調査できる限り、MailMessageのMemoryStreamを得る他の方法はありません。以前の記事でもプライベートAPIメソッドを使用していましたが、サードパーティベンダーの例でもこのプライベートAPIメソッドを使用しています。誰でも公開APIを使用してこれを行う方法を知っていれば、それを共有する大きな助けになるでしょう:) – dimoss

+0

こんにちは、私はcloseMethod.Invoke(mailWriter、BindingFlags.Instance | BindingFlags.NonPublic、null、newオブジェクト[] {}、ヌル); ...任意のヒント?ありがとう – VAAA

0

余分なTRUEを備えた提案されたソリューションは美しく機能します。

VS2012でプロジェクトを実行しているときにエラーが発生しましたが、すべてのライブラリで.net 4.5ではなく4.0を使用しています。

エラーはVS2012をインストールしたマシンでのみ発生し、VS2012はデバッグ中に.net 4.5を参照するように見えます。 .net 4.0を実行しているクライアントでアプリケーションをデプロイして実行すると、すべて正常に動作します。

したがって、4.0を実行する場合は、4.5を実行すると余分なTRUEを追加しないでください。

+0

ええ私もこれに遭遇した。コンパイラの条件を入れて、コードをデバッグして本番環境で動作させる必要がありました。 – efbenson

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

回避策があり、さらにAPIバージョンを使用する可能性があります。ありがとう! – antlersoft

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

これは.NET 4.0と4.5で私にとって役に立ちました。ありがとう! – LuckyStrike

関連する問題