Как использовать MODI в веб-приложении ASP.Net? - PullRequest
10 голосов
/ 28 августа 2009

Я написал библиотеку-оболочку OCR для COM-интерфейса Microsoft Office Document Imaging, и в консольном приложении, работающем локально, оно работает безупречно при каждом тесте.

К сожалению, все начинает идти плохо, когда мы пытаемся интегрировать его со службой WCF, работающей как веб-приложение ASP.Net, под IIS6. У нас были проблемы с попыткой освободить COMI-объекты MODI, и в Интернете было много примеров, которые помогли нам.

Однако проблемы все еще остаются. Если я перезапущу IIS и заново разверну веб-приложение, первые несколько попыток 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();
    }
}

Затем я создаю экземпляр экземпляра ImageReader внутри блока using (который будет вызывать IDisposable.Dispose при выходе)

Вызов Marshal.FinalReleaseComObject должен дать CLR команду высвободить COM-объекты, и поэтому я не могу понять, что может послужить причиной появления у нас симптомов.

Для чего стоит запускать этот код вне IIS, скажем, в Консольном приложении, все кажется пуленепробиваемым. Работает каждый раз.

Любые советы, которые помогут мне диагностировать и решить эту проблему, будут огромной помощью, и я буду сумасшедшим! ; -)

Спасибо!

Ответы [ 4 ]

4 голосов
/ 09 сентября 2009

Задумывались ли вы о размещении OCR-части вашего приложения вне процесса .

Наличие услуги может дать вам тонны гибкости:

  1. Вы можете определить простую конечную точку для вашего веб-приложения и получить к ней доступ через удаленное взаимодействие или WCF.
  2. Если материал имеет грушевидную форму и вся библиотека уворачивается, вы можете заставить службу запускать отдельный процесс каждый раз, когда вам нужно выполнить OCR. Это дает вам максимальную безопасность, но требует небольших дополнительных затрат. Я бы предположил, что OCR НАМНОГО дороже, чем ускорение процесса .
  3. Вы можете хранить экземпляр вокруг COM-объекта, если память начинает протекать, вы можете перезагрузить себя, не влияя на веб-сайт (если вы осторожны).

Лично я нашел в прошлом взаимодействие COM + IIS = горе.

1 голос
/ 26 ноября 2010

Мне пришлось столкнуться с этой ошибкой неделю назад, и после тестирования некоторых решений, приведенных здесь, я наконец-то решил проблему. Я объясню здесь, как я это сделал.

В моем случае у меня служба Windows, выполняющая и обрабатывающая документы из папки, проблема возникает, когда существует более 20 документов, выдавая ошибку: Исключение из HRESULT: 0x80010105 (RPC_E_SERVERFAULT).

В моем коде я вызывал метод каждый раз, когда я определяю документ в папке, я делаю экземпляр документа MODI (MODI.Document _document = new MODI.Document ();) и обрабатываю файл, и это что вызвало ошибку !!

Решение состояло в том, чтобы иметь только один глобальный экземпляр MODI.Document и обрабатывать все документы без него, таким образом, у меня все время работает только один экземпляр для моей службы.

Надеюсь, это поможет тем, кто сталкивается с той же проблемой.

1 голос
/ 09 сентября 2009

Можете ли вы повторить проблему в небольшом консольном приложении? Может быть, оставить его спать на 30 минут и вернуться к нему?

Лучший способ решить такие вещи - это полностью изолировать их. Мне было бы интересно посмотреть, как это работает.

1 голос
/ 28 августа 2009

MODI невероятно выигрышен, когда дело доходит до избавления от самого себя, особенно при работе в IIS. По своему опыту я обнаружил, что, хотя все это замедляется, единственный способ избавиться от этих ошибок - это добавить GC.WaitForPendingFinalizers () после вашего вызова GC.Collect (). Если вам интересно, я написал статью об этом.

...