Проблема производительности с циклом For в VSTO C# при получении электронных писем из outlook

#c# #outlook #vsto

Вопрос:

У меня возникли проблемы с циклическим просмотром электронных писем в папках входящих сообщений Outlook (C# VSTO добавить в Outlook). Я использовал цикл foreach, но он потребляет много памяти, а затем вызывает исключение: не хватает ресурсов системы/памяти. Итак, сейчас я использую цикл for, который не вызывает этой ошибки, но для одной из папок он действительно медленный, читает менее 5-8 писем в секунду. Эта папка содержит чуть более 100 000 электронных писем. Для всех остальных папок скорость составляет 30-35 писем.

Код таков:

 Static void IterateMessages(Outlook.Folder folder){

        int tempCount = folder.Items.Count;
        if (folder.Items != null)
        {
            Object item;
            for (int k = 1; k <= tempCount; k  )
            {
                item = folder.Items[k];
                if (item is Outlook.MailItem)
                {
                    emailCount  ;
                    try
                    {
                        SaveAttachment(item);
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine("An error occurred Iterate Message: '{0}'", e);
                    }
                }
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(item);
                item = null;
            }
            tempCount = 0;
        }
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(folder);
    }
 

Было бы здорово, если бы кто-нибудь мог помочь с этим вопросом. При использовании цикла foreach скорость составляла около 40-45 электронных писем в секунду. Кроме того, этот метод вызывается из другого цикла for, который перебирает папки, заранее спасибо

Ответ №1:

Во-первых, перебирать все элементы в папке не очень хорошая идея. Тебе действительно нужно это делать?

Вы продолжаете извлекать коллекцию элементов в цикле ( folder.Items[k] ). Кэш Items перед входом в цикл:

 Items items = folder.Items;
for (int k = 1; k <= items.Count; k  )
{
  object item = items[k];
  ...
}
Marshal.ReleaseComObject(items);
 

Вы просачиваете ссылки (они, конечно, позже будут выпущены GC), но так как вы используете FinalReleaseComObject…

 object item = items[k];
MailItem mailItem = item as MailItem;
if (mailItem != null)
{
  ...
  Marshal.ReleaseComObject(mailItem);
}
Marshal.ReleaseComObject(item);
 

Комментарии:

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

2. Кроме того, я внедрю ваше решение и посмотрю, имеет ли оно какое-то значение

3. Спасибо, это сделало все быстрее

Ответ №2:

Правильного освобождения базовых COM-объектов недостаточно для вашей цели. Вместо перебора всех элементов в папке вам нужно использовать методы Find / FindNext или Restrict Items класса для поиска элементов с вложениями, и только тогда вы сможете перебирать все элементы только с вложениями. В запросе может использоваться нотация SQL (VBA):

 query ="@SQL=" amp; chr(34) amp; "urn:schemas:httpmail:hasattachment" amp; chr(34) amp; "=1"
 

Подробнее об этих методах читайте в следующих статьях:

Также вы можете найти AdvancedSearch полезным метод класса приложения. Ключевыми преимуществами использования этого AdvancedSearch метода в Outlook являются:

  • Поиск выполняется в другом потоке. Вам не нужно запускать другой поток вручную, так AdvancedSearch как метод запускает его автоматически в фоновом режиме.
  • Возможность поиска любых типов товаров: почта, встреча, календарь, заметки и т.д. в любом месте, т. е. за пределами определенной папки. Методы Restrict и Find / FindNext могут быть применены к определенной Items коллекции (см. Items Свойство Folder класса в Outlook).
  • Полная поддержка запросов DASL (пользовательские свойства также могут использоваться для поиска). Вы можете прочитать больше об этом в статье о фильтрации в MSDN. Для повышения производительности поиска можно использовать ключевые слова мгновенного поиска, если для магазина включен мгновенный поиск (см. IsInstantSearchEnabled Свойство Store класса).
  • Вы можете остановить процесс поиска в любой момент, используя Stop метод Search класса.

См. раздел Расширенный поиск в Outlook программно: C#, VB.NET для получения дополнительной информации.