Синхронизация почтового ящика и веб-службах Exchange

Узнайте, как работает синхронизация почтовых ящиков при доступе к Exchange с помощью веб-служб Exchange (EWS).

EWS в Exchange получает содержимое почтовых ящиков и его изменения при помощи двух видов синхронизации:

  • Синхронизация папок
  • Синхронизация элементов

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

Синхронизация папок и элементов

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

Таблица 1. Операции EWS и методы управляемого API EWS для синхронизации папок и элементов

Операция служб EWS Метод управляемого API EWS
SyncFolderHierarchy Метод ExchangeService.SyncFolderHierarchy
SyncFolderItems Метод ExchangeService.SyncFolderItems

Область синхронизации следующим образом зависит от того, проводится ли начальная или непрерывная синхронизация:

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

Каждый метод синхронизации или операция синхронизации возвращает не саму изменившуюся папку или сообщение, а список изменений. Об изменениях элементов и папок сообщается с помощью следующих типов изменений:

  • Создать — указывает на то, что на клиенте должны быть созданы новый элемент или папка.
  • Обновить — указывает на то, что элемент или папка должны быть изменены на клиенте.
  • Удалить — указывает, что элемент или папка должны быть удалены на клиенте.
  • ReadStateChange для EWS или ReadFlagChange для управляемого API EWS указывает на то, что состояние чтения элемента изменилось с непрочитанного на прочитанный или с прочитанного на непрочитанный.

В Exchange Online, Exchange Online в составе Office 365 и версиях Exchange начиная с Exchange 2010 SP2 элементы и папки возвращаются в обратном хронологическом порядке, от новых к старым. В предыдущих версиях Exchange элементы и папки возвращаются в хронологическом порядке, от старых к новым.

Как работает синхронизация EWS?

Если вы впервые синхронизируете почтовый ящик, используйте процесс, показанный на рисунке 1. Можно использовать и другие конструктивные шаблоны синхронизации, но для масштабируемых приложений мы рекомендуем этот подход.

Рис. 1. Шаблон проектирования начальной синхронизации

Иллюстрация, показывающая шаблон проектирования начальной синхронизации. Клиент вызывает методы SyncFolderHierarchy и Load или GetItem, чтобы получить папки, затем вызывает методы SyncFolderItems и LoadPropertiesForItems или GetItem, чтобы получить элементы каждой папки.

Если для синхронизации почтового ящика используется существующее состояние синхронизации на клиенте, рекомендуется реализовать конструктивный шаблон, как показано на рисунке 2.

Рис. 2. Шаблон проектирования текущей синхронизации

Иллюстрация, показывающая шаблон проектирования текущей синхронизации. Клиент получает уведомление, а затем вызывает метод SyncFolderHierarchy или SyncFolderItems, получает свойства, после чего обновляет клиент или флаг чтения.

Конструктивные шаблоны синхронизации

Для своевременного обновления почтовых ящиков можно использовать один из двух конструктивных шаблонов синхронизации в приложении: синхронизацию на основе уведомлений или только синхронизацию.

Синхронизация на основе уведомлений, как показано на рисунке 2, основана на уведомлениях, предупреждающих клиента об обращении к методам управляемого API EWS SyncFolderItems или SyncFolderHierarchy или к операциям EWS SyncFolderHierarchy или SyncFolderItems. Этот тип синхронизации обычно рекомендуется для масштабируемых приложений, но не является универсально оптимальным подходом. Синхронизация на основе уведомлений имеет следующее преимущество:

уведомления оптимизируются, чтобы уменьшить количество обращений к базе данных Exchange на сервере. Очереди событий и подписки управляются сервером почтовых ящиков (или сервером клиентского доступа в Exchange 2010 и Exchange 2007); однако управление событиями и подписками использует меньше ресурсов, чем альтернативный вариант – более частые обращения к базе данных Exchange с целью синхронизации. Кроме того, Exchange имеет определенные регулирующие политики для уведомлений и подписок, обеспечивающие умеренное потребление ресурсов.

Однако у синхронизации на основе уведомлений есть и некоторые недостатки:

  • уведомления создают лишний "шум", так как большинство сценариев предусматривает несколько уведомлений для одного намерения пользователя. Это особенно актуально для папки "Календарь". Например, при получении одного запроса на собрание создается несколько уведомлений об элементах и папках, включая уведомление о создании элемента и отдельное уведомление об изменении элемента. Один из способов свести этот недостаток к минимуму — создать задержку в несколько секунд в вызовах Load, LoadPropertiesForItems, GetItem и GetFolder. В случае запроса на собрание, если вы вызываете операцию GetItem немедленно, может потребоваться один вызов для создания элемента и еще один для его изменения. Вместо этого, задержав вызов, можно вызвать операцию GetItem один раз и получить изменения, включающие одновременно и создание, и изменение элемента.
  • Уведомления ставятся в очередь на сервере почтовых ящиков, и подписки сохраняются там же. Если управляющий подпиской сервер почтовых ящиков недоступен, вы потеряете новые уведомления, ваш почтовый ящик не будет синхронизироваться, и вам придется повторно подписываться на уведомления.
  • Советуем спланировать стратегии минимизации последствий на случай сбоя уведомлений. Таким образом, второй подход, с конструктивным шаблоном только для синхронизации, является более устойчивым, чем синхронизация на основе уведомлений, так как он требует только, чтобы клиент поддерживал состояние синхронизации — потеря связи с сервером почтовых ящиков, управляющим подпиской, не создаст дополнительных проблем.

Если конструктивный шаблон подписки на основе уведомлений реализован согласно рекомендациям, он зависит от:

  • Уведомления для определения времени изменения данных.
  • Методы SyncFolderHierarchy или SyncFolderItems управляемого API EWS, а также операции EWS SyncFolderHierarchy или SyncFolderItems для определения того, что изменилось, оптимизируя количество возвращаемых событий синхронизации. Был ли новый элемент создан, обновлен или удален? Это единственная информация, которую можно получить от упомянутых методов. Не рассчитывайте узнать от них список свойств изменений. (Не вызывайте GetItem и LoadPropertiesForItems для всех возвращенных элементов или папок).
  • Использование методов Load или LoadPropertiesForItems в управляемом API EWS или операции GetItem EWS для определения изменения данных и извлечения свойств с сервера при необходимости, упорядочивая пакетные запросы на основе объема возвращаемых данных. После этого свойства на клиенте сравниваются со свойствами, только что возвращенными с сервера, и после этого элемент или папка создается, удаляется или изменяется на клиенте.

Подход "только синхронизация" полностью зависит от методов управляемого API EWS SyncFolderItems и SyncFolderHierarchy или от операций EWS SyncFolderHierarchy и SyncFolderItems, которые можно вызывать либо непрерывно, либо в определенное заданное время. У этого подхода тоже есть свои плюсы и минусы. Подход "только синхронизация" более устойчив, так как состояние синхронизации хранится на клиенте на уровне почтовых ящиков, и при этом не требуется уникального отношения между состоянием синхронизации и каким-либо сервером почтовых ящиков, поддерживающим подписку на уведомления. Метод синхронизации позволяет пережить сбой в почтовом ящике, так как он не зависит от сервера почтовых ящиков. Однако подход с синхронизацией увеличивает задержку для пользователя, так как элементы синхронизируются в определенное время или периодически, а не в режиме реального времени по мере получения элементов. Этот подход также связан с большими затратами, так как запросы к базе данных Exchange производятся даже тогда, когда, возможно, никаких изменений не произошло.

Советы и рекомендации по конфигурации

Для хорошо масштабируемых приложений мы советуем применять следующие рекомендации для синхронизации почтовых ящиков в приложении:

  • При вызове метода управляемого API EWS SyncFolderItems или SyncFolderHierarchy используйте значение IdOnly для параметра propertySet, а при использовании операций EWS SyncFolderHierarchy и SyncFolderItems используйте значение IdOnly для значения BaseShape, чтобы свести к минимуму обращения к базе данных Exchange. Чем больше свойств запрашивается в наборе свойств вызова SyncFolderItems или SyncFolderHierarchy, тем больше будет создаваться дополнительных серверных вызовов. Для каждого запрашиваемого значения свойства выполняется новый вызов RPC, в то время как для получения всех ItemIds для запроса выполняется всего один вызов RPC, независимо от количества результатов, которые необходимо передать. Поэтому запрос IdOnly генерирует одно обращение к базе данных, в то время как запрос пакета свойств темы и отправителя - три: одно для темы, одно для отправителя и одно для ItemId.

  • Не вызывайте методы управляемого API EWS Load или LoadPropertiesForItems и операции EWS GetItem или GetFolder отдельно для каждого элемента в ответе на синхронизацию. Вместо этого проанализируйте результаты; ища изменения, которые не требуют получения всех свойств, например изменения состояния прочитано/не прочитано. Если ответ включает изменение состояния прочитано/не прочитано, достаточно изменить только флажок на клиенте; не нужно получать все свойства элемента. Позаботьтесь о том, чтобы одна и та же работа не делалась несколько раз, то есть чтобы не вносились несколько раз изменения, исходящие от одного и того же клиента. Например, если ответ синхронизации предусматривает удаление элемента и удаление произошло на локальном клиенте, не нужно удалять сообщение еще раз или получать все свойства для этого элемента.

  • Чтобы избежать отклонения запросов в результате регулирования, поступайте следующим образом:

    • При вызове метода управляемого EWS API LoadPropertiesForItems или операции EWS GetItem, чтобы получить элементы в пакете, не объединяйте слишком много элементов в один пакет запроса; в противном случае запрос может быть отклонен в результате регулирования. Рекомендуется включать в пакет по 10 элементов.
    • Не делайте слишком много запросов за короткий интервал времени. Запросы могут быть отклонены в результате регулирования, и в результате отклик не ускорится, а замедлится.
    • Если вы объединяете элементы в пакеты, объедините в один пакет все элементы с одинаковыми значениями атрибутов Id и ChangeKey элемента FolderId.
    • Если ваши запросы начнут отклоняться в результате регулирования, прекратите их отправлять. Повторная отсылка запросов лишь затянет процесс восстановления. Вместо этого подождите, пока истечет время ожидания, а затем попробуйте отправить запросы на синхронизацию еще раз.
  • В зависимости от типа полученного уведомления о событии:

    • Для событий NewMail (новые сообщения) или Modified (изменения) вызовите метод управляемого API EWS SyncFolderItems или операцию EWS SyncFolderItems, так как уведомления не предоставляют ChangeKey и не вызывают изменений состояния "Прочитано/Не прочитано".
    • Для событий Deleted (удаления), если подписка на уведомление была активна до предыдущей синхронизации, просто удалите событие локально. Сразу после удаления не нужно вызывать метод управляемого API EWS SyncFolderItems или операцию EWS SyncFolderItems.
    • Если событие Modified (изменение) было вызвано изменением состояния "Прочитано/Не прочитано", не вызывайте метод управляемого API EWS LoadPropertiesForItems или операцию EWS GetItem, а просто измените флажок элемента.
  • При синхронизации данных календаря выполните следующие действия:

    • Используйте подход, аналогичный синхронизации на основе уведомлений. Поскольку SyncFolderItem не включает логику календаря, для просмотра встреч между двумя датами используйте метод управляемого API EWS FindAppointments или операцию EWS FindItem с элементом CalendarView, а затем вызовите метод управляемого API EWS LoadPropertiesForItems или операцию EWS GetItem, чтобы получить свойства элемента календаря.

    • Не проводите опрос элемента CalendarView с помощью метода управляемого API EWS FindAppointments или операции EWS FindItem.

  • При синхронизации папок поиска:

    • Используйте подход, аналогичный синхронизации на основе уведомлений.

    • Используйте уведомления, чтобы узнавать, когда данные изменились.

    • Так как в папке поиска нельзя использовать SyncFolderItem, чтобы определить, что изменилось, используйте отсортированный постраничный метод управляемого API EWS FindItems или операцию EWS FindItem с набором элементов FractionalPageItemView и SortOrder.

    • Для получения данных используйте метод управляемого API EWS LoadPropertiesForItems или операцию EWS GetItem.

Фильтрованная синхронизация

Метод управляемого API EWS SyncFolderItems и операция EWS SyncFolderItems позволяют игнорировать определенные элементы по их идентификаторам ItemIds, задав параметр ignoreItemIds в управляемом API EWS или элемент Ignore в EWS. Это идеально в тех случаях, когда, например, сотрудники начинают отвечать всем адресатам электронного сообщения, разосланного всем в компании.

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

  • Используйте конструктивный шаблон подписки на основе уведомлений.
  • Чтобы состояние синхронизировалось с текущим, повторно вызывайте методы SyncFolderItems и SyncFolderHierarchy с параметром propertySet, равным IdOnly. Или, если используется EWS, повторно вызывайте операции SyncFolderHierarchy и SyncFolderItems с параметром BaseShape, равным IdOnly.
  • Ответ просто удалите (без анализа и без сравнения свойств).
  • Используйте метод управляемого API EWS FindItems или операцию EWS FindItem, а также сортируйте и разбивайте на страницы результаты, чтобы предварительно заполнить элементы в представляющей интерес фильтруемой области.
  • Используйте состояние синхронизации, чтобы продолжать вызовы метода управляемого API EWS SyncFolderItems или операции EWS SyncFolderItems, но отслеживайте только изменения в наборе фильтруемых элементов. Если создаются новые элементы, необходимо узнать, находятся ли эти новые элементы в фильтруемой области.

В этой статье

См. также