J'essaie d'écrire une application qui surveillera quelques boîtes aux lettres et quand le courrier est trouvé, saisissez des informations sur chaque élément, puis une fois que j'ai une liste des éléments que je peux prendre le actes. Mais peu importe comment je l'approche, je frappe la limite de connexions RPC 255 forcée par Exchange.Exception lors de l'énumération des éléments Outlook en C#
Je suis absolument bloqué quant à ce qui cause l'erreur - autant que je peux voir que j'ai tout attaché dans une méthode et j'appelle Marshal.ReleaseComObject .... J'accepte même la performance hit d'ouverture et de fermeture du gestionnaire Outlook Application lui-même.
Tout conseil serait apprécié massivement ... (je ne peux pas à comprendre pourquoi mon code semble erroné dans l'aperçu ainsi pour des raisons de sécurité, je l'ai mis sur pastebin aussi ... 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;
}
}
}
Appelez-vous ce code à partir de plusieurs threads? –
Il me semble que ce serait plus facile si vous utilisiez l'API Exchange 2007 (activée en tant que service Web) ou un simple protocole d'accès aux boîtes aux lettres comme POP3 ou IMAP si le serveur de messagerie cible le prend en charge. J'ai déjà utilisé ces deux méthodes avec aisance auparavant, mais je trouve que programmer des programmes MS Office via COM était une ressource à tout faire. Mais malheureusement, je ne peux pas commenter beaucoup sur le problème spécifique avec ce peu de code ... – ewall
@JP Alioto - le code est appelé à partir d'un seul thread et n'a aucun problème si je supprime l'appel à la méthode qui ouvre l'élément pour obtenir le corps. @ewall - Je me pencherai sur l'API Exchange 07 mais je ne l'ai pas utilisée (ou POP/IMAP) auparavant et je me sens tellement proche de cette solution que j'aimerais la réparer :) –