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) で
この時点から、IIS をリセットするまで、すべての要求は OCR を実行できず、サイクルが再び開始されます。
このアプリケーションは独自のアプリケーション プールで実行され、ローカル管理者権限を持つ ID の下で実行されます。
更新: この問題は、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 の外部で、たとえばコンソール アプリで実行すると、すべてが防弾のように見えることです。毎回動作します。
この問題を診断して解決するのに役立つヒントは、非常に役立ちます。私は狂ったように賛成します! ;-)
ありがとう!