2010-01-27 48 views
1

我正在嘗試編寫一個應用程序,它將監視幾個郵箱,並且在發現郵件時從每個項目中獲取一些信息,然後一旦我列出了可以採取的項目動作。枚舉C#中的Outlook項目時出現異常

但是無論我如何處理它,我都會觸發Exchange執行255個RPC連接限制。

我對導致錯誤的原因絕對堅持 - 據我所見,我已經把一切都捆綁在一個方法中,並打電話給Marshal.ReleaseComObject ....我甚至接受性能打開和關閉Outlook應用程序自身。

任何建議,將大規模感激...(我似乎無法弄清楚,爲什麼我的代碼看起來錯在預覽所以爲了安全起見,我把它放在引擎收錄太... http://pastebin.com/m637eb95

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Office.Interop.Outlook; 
using Microsoft.Office.Interop; 
using System.Runtime.InteropServices; 

namespace HandleMailingResponses 
{ 
    class OutlookFolderTableScraper 
    { 
     public List<OutlookItem> GetItemsFromFolder(string folderName) 
     { 
      List<OutlookItem> returnList = new List<OutlookItem>(); 

      Application outlookHandle = new Application(); 
      NameSpace outlookNamespace = outlookHandle.GetNamespace("MAPI"); 
      Folders rootOutlookFolders = outlookNamespace.Folders; 

      outlookNamespace.Logon(null, null, null, true); 

      Folder requestedRoot = enumerateFolders(rootOutlookFolders, folderName); 
      Folders theseFolders = requestedRoot.Folders; 
      Folder thisInbox = enumerateFolders(theseFolders, "Inbox"); 

      Marshal.ReleaseComObject(requestedRoot); 
      requestedRoot = null; 
      Marshal.ReleaseComObject(rootOutlookFolders); 
      rootOutlookFolders = null; 

      string storeID = thisInbox.StoreID; 

      Table thisTable = thisInbox.GetTable("",OlTableContents.olUserItems); 

      //By default each item has the columns EntryID, Subject, CreationTime, LastModificationTime and MessageClass 
      //we can add any of the other properties the MailItem or ReportItem object would have.... 
      Columns theseColumns = thisTable.Columns; 
      theseColumns.Add("SenderEmailAddress"); 

      Marshal.ReleaseComObject(thisInbox); 
      thisInbox = null; 

      outlookNamespace.Logoff(); 
      Marshal.ReleaseComObject(outlookNamespace); 
      outlookNamespace = null; 
      outlookHandle.Quit(); 
      Marshal.ReleaseComObject(outlookHandle); 
      outlookHandle = null; 

      int count = 0; 
      while (!thisTable.EndOfTable) 
      { 
       Row thisRow = thisTable.GetNextRow(); 
       object[] theseValues = (object[]) thisRow.GetValues(); 
       Console.WriteLine("processed {0}",count++); 

       //get the body from this item 
       string messageClass = (string)theseValues[4]; 
       string entryID = (string)theseValues[0]; 
       string body = getItemBody(entryID,storeID, messageClass); 

       returnList.Add(new OutlookItem((string)theseValues[5], (string)theseValues[1], body, messageClass, entryID)); 
      } 



      return returnList; 
     } 

     private string getItemBody(string entryID, string storeID, string messageClass) 
     { 
      Application outlookHandle = new Application(); 
      NameSpace outlookNamespace = outlookHandle.GetNamespace("MAPI"); 
      outlookNamespace.Logon(null, null, null, true); 
      string body; 

      if (messageClass.ToLower().StartsWith("report")) 
      { 
       ReportItem thisItem = (ReportItem)outlookNamespace.GetItemFromID(entryID, storeID); 
       body = thisItem.Body; 
       thisItem.Close(OlInspectorClose.olDiscard); 
       //release this com reference 
       int releaseResult; 
       do 
       { 
        releaseResult = Marshal.ReleaseComObject(thisItem); 
       } while (releaseResult != 0); 
      } 
      else 
      { 
       MailItem thisItem = (MailItem)outlookNamespace.GetItemFromID(entryID, storeID); 
       body = thisItem.Body; 
       thisItem.Close(OlInspectorClose.olDiscard); 
       //release this com reference 
       int releaseResult; 
       do 
       { 
        releaseResult = Marshal.ReleaseComObject(thisItem); 
       } while (releaseResult != 0); 
      } 

      outlookNamespace.Logoff(); 
      outlookNamespace = null; 
      outlookHandle.Quit(); 
      outlookHandle = null; 


      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 

      return body; 
     } 

        /// <summary> 
     /// Iterates through an Outlook.Folders object searching for a folder with the given name 
     /// </summary> 
     /// <param name="rootFolder">An Outlook.Folder object</param> 
     /// <param name="targetFolder"></param> 
     /// <returns></returns> 
     private Folder enumerateFolders(Folders rootFolders, string targetFolder) 
     { 
      Folder returnFolder = null; 
      System.Collections.IEnumerator thisEnumerator = rootFolders.GetEnumerator(); 
      while (thisEnumerator.MoveNext()) 
      { 
       Folder f = (Folder)thisEnumerator.Current; 
       string name = f.Name; 
       if (targetFolder.ToLower().Equals(name.ToLower())) 
       { 
        returnFolder = f; 
        break; 
       } 
      } 
      ICustomAdapter adapter = (ICustomAdapter)thisEnumerator; 
      Marshal.ReleaseComObject(adapter.GetUnderlyingObject()); 
      adapter = null; 
      return returnFolder; 
     } 
     } 

} 
+0

你是否從多個線程調用此代碼? – 2010-01-27 00:45:38

+0

對我來說,如果您使用Exchange 2007 API(作爲Web服務啓用)或簡單的郵箱訪問協議(如POP3或IMAP)(如果目標郵件服務器支持它),那麼編碼和資源需求會更輕鬆。我之前很輕鬆地使用了這兩種方法,但是發現通過COM編程MS Office程序是最好的方法。但遺憾的是,我無法對這一點代碼的具體問題發表太多評論...... – ewall 2010-01-27 00:52:51

+0

@JP Alioto - 從單個線程調用代碼,並且如果我刪除對打開項目的方法的調用,則沒有問題得到身體。 @ewall - 我會研究Exchange 07 API,但之前我沒有使用它(或POP/IMAP),我覺得這個解決方案非常接近,我很想修復它:) – 2010-01-27 10:22:51

回答

1

我的要求與您的要求幾乎相同。下面的示例應用程序是非常好的參考:

http://www.c-sharpcorner.com/UploadFile/rambab/OutlookIntegration10282006032802AM/OutlookIntegration.aspx

關於「交易所強制執行255 RPC連接限制」選中這些鏈接:
http://www.dimastr.com/Redemption/faq.htm
http://www.outlookcode.com/threads.aspx?forumid=2&messageid=26321

+0

This isn'這真的是答案,但最終我以贖罪去了。它大量簡化了我的代碼,最重要的是它的工作。 – 2010-02-09 13:22:25

0

不要創建每一個新的應用程序對象當你調用這個函數時,把它作爲你的類的一個私有成員變量,直到你不再需要它爲止。這樣你只需要在你的構造函數中調用Namespace.Logon。

+0

@McAden - 我將應用程序和名稱空間調用移到了方法中,希望關閉它們將允許系統正確釋放COM對象。 如果我刪除了對Item.Body的調用,應用程序將遍歷所有5000多個項目,因此我確信問題在於如何釋放對象 – 2010-01-27 10:26:58

+0

如果您使這些對象成爲靜態,您可以在這些對象上調用Marshal.ReleaseComObject ,在AppDomain.CurrentDomain.DomainUnload等事件處理程序中。 AppDomain肯定有這樣的事件。 – 2013-02-06 20:19:14