. NET приложение случайно завершает работу при открытии сеанса Lotus Notes - PullRequest
1 голос
/ 15 апреля 2020

Мы создали приложение. NET, которое собирает данные из IBM (Lotus) Notes. Он подключается к Notes через COM-объекты (Lotus Domino Objects).

В общем, он работает и выполняет все необходимые операции, но затем, после нескольких часов работы, приложение перестает работать. Я имею в виду, это как бы зависает и перестает выполнять какую-либо работу. Это происходит в разных базах данных в непредсказуемое время, поэтому я не смог найти никакой регулярности

Последнее сообщение журнала, которое мы получили из приложения:

System.Runtime.InteropServices.COMException (0x80010105): Создание экземпляра компонента COM с CLSID {29131539-2EED-1069-BF5D-00DD011186B7} из IClassFactory не выполнено из-за следующей ошибки: 80010105 Сервер выдал исключение. (Исключение из HRESULT: 0x80010105 (RPC_E_SERVERFAULT)). на System.RuntimeTypeHandle.CreateInstance (типа RuntimeType, Boolean, Boolean publicOnly NOCHECK, Boolean & canBeCached, RuntimeMethodHandleInternal & CTOR, Boolean & bNeedSecurityCheck) в System.RuntimeType.CreateInstanceSlow (Boolean publicOnly, булевой skipCheckThis, булевой fillCache, StackCrawlMark & ​​stackMark) в System.Activator.CreateInstance (Тип type, Boolean nonPubli c) в System.Activator.CreateInstance (тип type) в MyMethod (NotesServerConfig notesServerConfig, String mailBox) в D: ... \ MyClass.cs: строка 164

или

System.Runtime.InteropServices.COMException (0x80040FA1): Исключение из HRESULT: 0x80040FA1 в Domino.ISession.Initialize (String pPassword) в MyMethod (NotesServerConfig notes String:: .. \ MyClass.cs: строка 164

Тот факт, что они оба имеют ссылку на строку 164 MyClass, которая является просто вызовом конструктора сеанса:

var session = new NotesSession();

Мое настоящее приложение работает как Windows Сервис через To pshelf, так что в нем много кода, так как проект уже стал довольно большим. Итак, позвольте мне привести здесь упрощенную версию без какого-либо дополнительного кода и сторонних библиотек, чтобы показать, как я использую Lotus Domino Objects:

using Domino;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace LotusTest
{
    class Program
    {
        private const int _maxClientReCreateAttempts = 10;

        private const string _password = "qwerty";
        private const string _server = "test.server.ru";

        private static readonly List<string> _dbNames = new List<string>
        {
            "mail\\test1", "mail\\test2", "mail\\test3"
        };

        static void Main(string[] args)
        {
            foreach (var dbName in _dbNames)
            {
                var folders = GetFolders(dbName);
                foreach (var folder in folders)
                {
                    var mailSubjects = GetEmailSubjects(folder, dbName);
                    foreach (var mailSubject in mailSubjects)
                    {
                        Console.WriteLine($"Mail {mailSubject} in {folder}, db: {dbName}");
                    }
                }
            }
        }

        private static List<string> GetFolders(string dbName)
        {
            var result = new List<string>();

            var session = new NotesSession();
            session.Initialize(_password);
            var db = session.GetDatabase(_server, dbName, false);

            if (db == null)
            {
                Console.WriteLine($"Can't read the database: {dbName}");
                return result;
            }

            foreach (var view in db.Views)
            {
                if (!view.IsFolder) { continue; }
                result.Add(view.Name);
            }

            return result;
        }

        private static List<string> GetEmailSubjects(string viewName, string dbName)
        {
            var result = new List<string>();

            var session = new NotesSession();
            session.Initialize(_password);

            var db = session.GetDatabase(_server, dbName, false);

            if (db == null)
            {
                Console.WriteLine($"Can't read the database: {dbName}");
                return result;
            }

            var cv = db.GetView(viewName);
            if (cv == null)
            {
                Console.WriteLine($"Can't read '{viewName}' folder of '{dbName}' database");
                return result;
            }

            return ReadFolder(cv, session, dbName, viewName);            
        }

        private static List<string> ReadFolder(NotesView cv, NotesSession session, string folder, string mailBox)
        {
            var result = new List<string>();
            var doc = cv.GetFirstDocument();

            int i = 0;
            int errCount = 0;
            bool lastGetWithError = false;
            int totalAmount = cv?.AllEntries?.Count ?? 0;

            int clientReCreateAttempts = 0;

            while (doc != null)
            {
                try
                {
                    if (!lastGetWithError)
                    {
                        result.Add(doc.GetItemValue("Subject")[0]);
                        Console.WriteLine($"Folder: {folder}, processed: {i + 1 - errCount} of {totalAmount}");   
                    }

                    doc = cv.GetNextDocument(doc);
                    lastGetWithError = false;
                }
                catch (COMException ex)
                {
                    Console.WriteLine($"Error on reading folder {folder} of mailbox {mailBox}.\r\n{ex}");
                    if (clientReCreateAttempts > _maxClientReCreateAttempts)
                    {
                        throw new Exception("Reading mail doc error: ", ex);
                    }
                    Console.WriteLine($"Trying to re-create Notes session");
                    session = new NotesSession();
                    clientReCreateAttempts++;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error on reading folder {folder} of mailbox {mailBox}.\r\n{ex}");
                    lastGetWithError = true;
                }
                finally
                {
                    i++;
                }
            }

            return result;
        }
    }
}

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

  1. Можно ли понять, что именно происходит за этими 0x80010105 (RPC_E_SERVERFAULT) и 0x80040FA1 ошибками?

  2. Исходя из кода, который я здесь разместил, правильно ли я использую NotesSession и другие объекты Lotus COM? Я имею в виду, нужно ли мне как-то утилизировать / освободить / закрыть сеанс (или другие объекты) после выполнения какой-либо операции et c?

Заранее спасибо!

...