10

我已经围绕 Microsoft Office Document Imaging COM API 编写了一个 OCR 包装库,并且在本地运行的控制台应用程序中,它在每次测试中都能完美运行。

可悲的是,当我们尝试将它与作为 IIS6 下的 ASP.Net Web 应用程序运行的 WCF 服务集成时,事情开始变得糟糕。我们在尝试释放 MODI COM 对象时遇到了问题,网上有很多例子对我们有帮助。

然而,问题仍然存在。如果我重新启动 IIS,并重新部署 Web 应用程序,前几次 OCR 尝试效果很好。如果我将其放置 30 分钟左右,然后再执行另一个请求,则会收到如下服务器故障错误:

服务器抛出异常。(来自 HRESULT 的异常:0x80010105 (RPC_E_SERVERFAULT)):在 MODI.DocumentClass.Create(String FileOpen)

从这一点开始,每个请求都将无法执行 OCR,直到我重置 IIS,然后循环再次开始。

我们在它自己的应用程序池中运行这个应用程序,它以具有本地管理员权限的身份运行。

更新:这个问题可以通过在进程外执行 OCR 来解决。似乎 MODI 库不能很好地处理托管代码,当涉及到自身清理时,因此在我的情况下为每个 OCR 请求生成新进程效果很好。

这是执行 OCR 的函数:

    public class ImageReader : IDisposable
{
    private MODI.Document _document;
    private MODI.Images _images;
    private MODI.Image _image;
    private MODI.Layout _layout;
    private ManualResetEvent _completedOCR = new ManualResetEvent(false);

    // SNIP - Code removed for clarity

    private string PerformMODI(string fileName)
    {
        _document = new MODI.Document();
        _document.OnOCRProgress += new MODI._IDocumentEvents_OnOCRProgressEventHandler(_document_OnOCRProgress);
        _document.Create(fileName);

        _document.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, true, true);
        _completedOCR.WaitOne(5000);
        _document.Save();
        _images = _document.Images;
        _image = (MODI.Image)_images[0];
        _layout = _image.Layout;
        string text = _layout.Text;
         _document.Close(false);
        return text;
    }

    void _document_OnOCRProgress(int Progress, ref bool Cancel)
    {
        if (Progress == 100)
        {
            _completedOCR.Set();
        }
    }
    private static void SetComObjectToNull(params object[] objects)
    {
        for (int i = 0; i < objects.Length; i++)
        {
            object o = objects[i];
            if (o != null)
            {
                Marshal.FinalReleaseComObject(o);
                o = null;
            }
        }
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public void Dispose()
    {
        SetComObjectToNull(_layout, _image, _images, _document);
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

然后我在 using 块中实例化 ImageReader 的一个实例(它将在退出时调用 IDisposable.Dispose)

调用 Marshal.FinalReleaseComObject 应该指示 CLR 释放 COM 对象,所以我不知道是什么导致了我们的症状。

对于它的价值,在 IIS 之外运行此代码,例如控制台应用程序,一切似乎都是防弹的。它每次都有效。

任何可以帮助我诊断和解决此问题的提示都将是巨大的帮助,我会疯狂地投票!;-)

谢谢!

4

4 回答 4

4

您是否考虑过在进程外托管应用程序的 OCR 部分。

拥有一项服务可以为您提供大量的灵活性:

  1. 您可以为您的 Web 应用程序定义一个简单的端点,并通过远程处理或 WCF 访问它。
  2. 如果东西是梨形的并且图书馆都是躲闪的,你可以让服务在每次你需要执行 OCR 时启动一个单独的进程。这为您提供了极大的安全性,但需要少量的额外费用。我认为OCR 比启动进程要昂贵得多
  3. 您可以在 COM 对象周围保留一个实例,如果内存开始泄漏,您可以重新启动自己而不影响网站(如果您小心的话)。

就我个人而言,过去我发现 COM interop + IIS = grief。

于 2009-09-09T03:25:18.317 回答
1

MODI 在摆脱自身时非常不稳定,尤其是在 IIS 中运行。根据我的经验,我发现虽然它会减慢一切速度,但摆脱这些错误的唯一方法是在 GC.Collect() 调用之后添加 GC.WaitForPendingFinalizers() 。如果你有兴趣,我写了一篇关于这个的文章。

于 2009-08-28T14:06:13.830 回答
1

你能在一个小的控制台应用程序中复制这个问题吗?也许让它睡 30 分钟然后再回来?

解决此类问题的最佳方法是将其完全隔离。我很想看看它是如何工作的。

于 2009-09-09T01:27:09.040 回答
1

一周前我不得不处理这个错误,在测试了这里给出的一些解决方案之后,我终于解决了这个问题。我将在这里解释我是如何做到的。

在我的情况下,我有一个 Windows 服务正在运行和处理文件夹中的文档,当有超过 20 个文档时会出现问题,并抛出错误:HRESULT 异常:0x80010105 (RPC_E_SERVERFAULT)。

在我的代码中,每次检测到文件夹中的文档时,我都会调用一个方法,我创建一个 MODI 文档的实例(MODI.Document _document = new MODI.Document();)并处理该文件,这就是原因错误!!

解决方案是只有一个 MODI.Document 的全局实例,并用它处理所有文档,这样我就只有一个实例一直在为我的服务运行。

我希望这将帮助那些面临同样问题的人。

于 2010-11-26T13:37:13.503 回答