使用 RDO/MAPI 提取大型 public 文件夹存储并获取 E_MAPI_TOO_BIG

Using RDO/MAPI to extract large public folder stores and getting E_MAPI_TOO_BIG

我正在尝试使用 RDO 5.14 从 Exchange Server 2010 导出我公司相当大的 public 文件夹布局(000 个文件夹)的内容。

我遇到了很多人发现的问题,因为在某些时候 Exchange 2010 给出了错误 E_MAPI_TOO_BIG,因为我使用的用户已经违反了 exchange 存储限制 documented here

在许多情况下,公认的解决方案是在每个 ref 上调用 while (Marshal.ReleaseComObject(ref)>0),偶尔调用 GC.Collect(),这似乎允许处理更多项目,但仍然不允许我这样做收到超过 500 条消息。

有些人在玩弄代码。它揭示了以下令人惊讶的(至少对我而言)事实。

如果我像这样遍历文件夹中的项目就没有问题:

for (int i = 1; i < items.Count; ++i) {
    IRDOMail item = items.Item(i);
    string SUCCESS = item.EntryID;
}

但是,如果我在某个时候使用此代码示例,它会失败(在代码中的其他地方试图访问其他文件夹) E_MAPI_TOO_BIG:

for (int i = 1; i < items.Count; ++i) {
    IRDOMail item = items.Item(i);
    string FAIL = item.Subject;
}

此时我已经达到了我的 COM 技能的极限。它向我暗示,在 .NET InterOp 中取消引用 MailItem 的 COM 属性 的某些部分最终会获取我无法释放的引用。如果是这种情况,我不确定如何解决它,如果有的话?

如果我在没有 RDO 的情况下使用 MAPI,可以看到类似(但不同)的行为,进一步表明这是 MAPI (14.0) 的一个怪癖?

您需要使用 ReleaseComObject:

for (int i = 1; i < items.Count; ++i) {
    IRDOMail item = items.Item(i);
    string FAIL = item.Subject;
    Marshal.ReleaseComObject(item); 
}

事实证明这是程序结构的问题,而不是 RDO 或 MAPI 的直接问题。具体来说,问题是试图递归处理整个树 and 项目。

似乎从文件夹访问 MAPI/RDO MailItem 的任何 属性 都会创建从文件夹返回到项目的内部引用。虽然我不确定这是真的,也不知道如何验证。

因此,如果该结构的一个子分支(不仅仅是一个文件夹)包含超过 500 条消息,您会E_MAPI_TOO_BIG 尝试以所述方式'visit' 结构。

解决方案是使用递归构建文件夹 EntryId 的列表,然后使用 GetFolderFromId() 遍历该列表以获取文件夹,然后遍历项目。到目前为止,我发现的 MAPI/RDO 编程资源中的 None 提到了这个事实。

更新

在花费更多时间尝试让 MAPI 在托管代码中工作后,我得出的结论是尝试做我正在尝试的事情从根本上说是个坏主意。虽然上面的解决方案让我更进一步,但当我尝试访问消息的更多属性时,它最终再次失败(出现相同的错误)。

事后看来,问题似乎是它几乎可以正常工作,而且很多人都设法做到了这一点,因此有相当多的在线资源可以证明这一点。但是,由于 Microsoft 不支持在托管代码中执行 MAPI,因此我们一开始似乎站不住脚。即使这是 COM Interop 而不是直接 MAPI。

在我看来,使用 Exchange 进行任何规模的操作都需要使用其他 Exchange 技术之一。我最终使用了 EWS,它看起来很完整,更重要的是,它很可靠。我希望这对某人有所帮助!