Я написал библиотеку обложек OCR вокруг API-интерфейса Microsoft Office Document Imaging COM API, а в приложении консоли, работающем локально, он работает безупречно с каждым тестом.
К сожалению, все начинается плохо, когда мы пытаемся интегрировать его с сервисом WCF, работающим как веб-приложение ASP.Net, в рамках IIS6. У нас были проблемы с попыткой освободить MODI COM-объекты, и было много примеров в Интернете, которые помогли нам.
Однако проблемы все еще остаются. Если я перезапущу IIS и сделаю новое развертывание веб-приложения, первые несколько попыток OCR отлично работают. Если я оставлю это на 30 минут или около того, а затем сделаю еще один запрос, я получаю ошибки с ошибками сервера, например:
Сервер исключил исключение. (Исключение из HRESULT: 0x80010105 (RPC_E_SERVERFAULT)): в MODI.DocumentClass.Create(String FileOpen)
С этого момента каждый запрос не сможет выполнить OCR, пока я reset 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();
}
}
Затем я создаю экземпляр ImageReader внутри используемого блока (который вызовет IDisposable.Dispose при выходе)
Вызов Marshal.FinalReleaseComObject должен дать указание CLR освободить COM-объекты, и поэтому я не понимаю, что может вызвать симптомы, которые у нас есть.
За что стоит, запустив этот код за пределами IIS, скажем, в консольном приложении, все кажется пуленепробиваемым. Он работает каждый раз.
Любые подсказки, которые помогут мне диагностировать и решить эту проблему, будут огромной помощью, и я буду взят как сумасшедший!; -)
Спасибо!