Мы создали приложение. 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;
}
}
}
Итак, в соответствии с зависанием - возможно, это просто ошибка в моем исключении обработки. Но есть пара вещей, которые я хочу спросить:
Можно ли понять, что именно происходит за этими 0x80010105 (RPC_E_SERVERFAULT)
и 0x80040FA1
ошибками?
Исходя из кода, который я здесь разместил, правильно ли я использую NotesSession и другие объекты Lotus COM? Я имею в виду, нужно ли мне как-то утилизировать / освободить / закрыть сеанс (или другие объекты) после выполнения какой-либо операции et c?
Заранее спасибо!