Контакты С# Outlook VSTO дублируются при удалении

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

private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        string sTempPath = GetTemporaryDirectory();

        //RequestContacts();
        ExtractContacts(sTempPath);
        ImportContacts(sTempPath);
    }

«RequestContacts()» загружает контакты с сервера в виде zip-файла в каталог приложений.

public string GetTemporaryDirectory()
    {
        string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
        Directory.CreateDirectory(tempDirectory);
        return tempDirectory;
    }

Это просто находит временную папку для извлечения контактов, а затем импортирует их в Outlook.

private void ExtractContacts(string sExtractPath)
    {
        string sImportPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
        string sZipPath = sImportPath.Substring(6, sImportPath.Length - 6) + "/contacts.zip";
        ZipFile.ExtractToDirectory(sZipPath, sExtractPath);
    }

Это извлекает загруженные контакты из zip во временную папку.

private void ImportContacts(string sImportPath)
    {
        var oldContacts = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts).Items.Cast<Outlook.ContactItem>()
            .Where(c => c.ManagerName.Equals("QERP"));
        foreach (var oldContact in oldContacts)
        {
            oldContact.Delete();
        }

        var newContacts = Directory.GetFiles(sImportPath, "*.vcf").Select(Application.Session.OpenSharedItem).Cast<Outlook.ContactItem>();
        foreach (var newContact in newContacts)
        {
            newContact.ManagerName = "QERP";
            newContact.Save();
        }
    }

Это удаляет старые контакты, которые мы загрузили, а не контакты, которые мы не загрузили этим приложением.

Проблема в том, что он не удаляет все контакты. По какой-то причине он всегда удаляет половину + 1.


person iruoy    schedule 15.02.2016    source источник


Ответы (3)


Я бы рекомендовал начать с выпуска базовых COM-объектов и избегать использования нескольких точек в одной строке кода. Например:

 Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts).Items

Свойство Session класса Application возвращает экземпляр класса Namespace, который должен быть освобожден позже. Метод GetDefaultFolder класса Namespace возвращает экземпляр класса MAPIFolder, который также должен быть освобожден.

Используйте System.Runtime.InteropServices.Marshal.ReleaseComObject, чтобы освободить объект Outlook после завершения его использования. Это особенно важно, если ваша надстройка пытается перечислить более 256 элементов Outlook в коллекции, хранящейся на сервере Microsoft Exchange. Если вы не освободите эти объекты своевременно, вы можете достичь ограничения, установленного Exchange на максимальное количество элементов, открытых в любой момент времени. Затем задайте для переменной значение Nothing в Visual Basic (null в C#), чтобы освободить ссылку на объект. Подробнее об этом читайте в Систематический выпуск объектов".

    foreach (var oldContact in oldContacts)
    {
        oldContact.Delete();
    }

Вместо этого используйте цикл for. Это позволит мгновенно освобождать базовые COM-объекты в коде. Для удаления элементов Outlook я бы предложил использовать цикл while, где вы можете проверить количество элементов доступны или цикл for уменьшает счетчик.

person Eugene Astafiev    schedule 15.02.2016

Не используйте цикл foreach при удалении элементов - вы изменяете коллекцию, таким образом пропуская половину элементов. Используйте нисходящий цикл for

Outlook.Items items = oldContacts.Items;
for (int i = items.Count; i >= 1; i--)
{
   Outlook.ContactItem contact = items[i] as Outlook.ContactItem; 
   if (contact != null)  //could be a distribution list
   {
      contact.Delete();
   } 
}
person Dmitry Streblechenko    schedule 15.02.2016
comment
oldContacts — это ContactItem, поэтому вы не можете привести его к Outlook.Item. Я исправил это на данный момент, запустив foreach в цикле while, но я попытаюсь найти что-то лучше, подобное этому. - person iruoy; 17.02.2016
comment
Измените объявление oldContacts на var oldContacts = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts). - person Dmitry Streblechenko; 17.02.2016

Он работает и удаляет все контакты. Я кое-что выясняю. Помогите мне для чистого кодирования.

    private void Contact_Sil()
    {
        var Eski_Contacts = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts).Items.Cast<Outlook.ContactItem>();
        while ( Eski_Contacts.Count()>0)
        {
            Eski_Contacts = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts).Items.Cast<Outlook.ContactItem>();
            foreach (var oldContact in Eski_Contacts)
            {
                oldContact.Delete();
            }                
        }
    }
person user3628261    schedule 18.03.2016