在 Exchange 中使用 EWS 同步文件夹
了解如何使用 EWS 托管 API 或 EWS 获取文件夹列表或更改的文件夹列表,以便同步客户端。
Exchange 中的 EWS 使用项目同步和文件夹同步在客户端和服务器之间同步邮箱内容。 文件夹同步从根文件夹获取文件夹的初始列表,然后随着时间的推移,获取对这些文件夹所做的更改,并获取新文件夹。
如果使用 EWS 托管 API 执行文件夹同步,则首先使用 ExchangeService.SyncFolderHierarchy 方法获取根文件夹中文件夹的初始列表。 然后,在后续调用期间更新 cSyncState 参数的值,以获取新文件夹和已更改文件夹的列表。
若要使用 EWS 执行文件夹同步,请使用 SyncFolderHierarchy 操作请求根文件夹中文件夹的初始列表,分析响应,然后在将来的某个时候获取对根文件夹中的更改并分析响应。 客户端收到初始文件夹或更改的文件夹列表后,它会 在本地进行更新。 将来检索更改的方式和时间取决于应用程序使用的 同步设计模式 。
使用 EWS 托管 API 获取所有文件夹或更改的文件夹的列表
下面的代码示例演示如何获取根文件夹中的文件夹的初始列表,然后获取根文件夹中自上次同步以来发生的文件夹更改列表。 在对 ExchangeService.SyncFolderHierarchy 方法进行初始调用期间,将 cSyncState 值设置为 null。 方法完成后,在本地保存 cSyncState 值,以便在下一次 SyncFolderHierarchy 方法调用中使用。 在初始调用和后续调用中,通过使用 对 SyncFolderHierarchy 方法的连续调用,以 10 个批方式检索文件夹,直到不再保留任何更改。 此示例将 propertySet 参数设置为 IdOnly 以减少对 Exchange 数据库的调用,这是 同步的最佳做法。 在此示例中,我们假定 服务 是有效的 ExchangeService 对象绑定,并且 cSyncState 表示先前调用 SyncFolderHierarchy 返回的同步状态。
// Get a list of all folders in the mailbox by calling SyncFolderHierarchy.
// The folderId parameter must be set to the root folder to synchronize.
// The propertySet parameter is set to IdOnly to reduce calls to the Exchange database
// because any additional properties result in additional calls to the Exchange database.
// The syncState parameter is set to cSyncState, which should be null in the initial call,
// and should be set to the sync state returned by the previous SyncFolderHierarchy call
// in subsequent calls.
ChangeCollection<FolderChange> fcc = service.SyncFolderHierarchy(new FolderId(WellKnownFolderName.Root), PropertySet.IdOnly, cSyncState);
// If the count of changes is zero, there are no changes to synchronize.
if (fcc.Count == 0)
{
Console.WriteLine("There are no folders to synchronize.");
}
// Otherwise, write all the changes included in the response
// to the console.
// For the initial synchronization, all the changes will be of type
// ChangeType.Create.
else
{
foreach (FolderChange fc in fcc)
{
Console.WriteLine("ChangeType: " + fc.ChangeType.ToString());
Console.WriteLine("FolderId: " + fc.FolderId);
Console.WriteLine("===========");
}
}
// Save the sync state for use in future SyncFolderItems requests.
// The sync state is used by the server to determine what changes to report
// to the client.
string fSyncState = fcc.SyncState;
在服务器上检索新文件夹或更改的文件夹列表后, 在客户端上创建或更新文件夹。
使用 EWS 获取文件夹的初始列表
以下示例演示使用 SyncFolderHierarchy 操作获取初始文件夹层次结构的 XML 请求。 这也是 EWS 托管 API 在使用 SyncFolderHierarchy 方法检索初始文件夹列表时发送的 XML 请求。 SyncFolderHierarchy 操作的 SyncState 元素未包括在内,因为这是初始同步。 本示例将 BaseShape 元素设置为 IdOnly 以减少对 Exchange 数据库的调用,这是 同步的最佳做法。
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<t:RequestServerVersion Version="Exchange2013" />
</soap:Header>
<soap:Body>
<m:SyncFolderHierarchy>
<m:FolderShape>
<t:BaseShape>IdOnly</t:BaseShape>
</m:FolderShape>
<m:SyncFolderId>
<t:DistinguishedFolderId Id="root" />
</m:SyncFolderId>
</m:SyncFolderHierarchy>
</soap:Body>
</soap:Envelope>
以下示例演示服务器在处理 SyncFolderHierarchy 操作请求后返回的 XML 响应。 初始响应包括所有文件夹的 Create 元素,因为所有文件夹在初始同步期间都被视为新文件夹。 为了提高可读性,某些属性和元素的值已缩短,并且为简洁起见,删除了一些 Create 元素块。
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo MajorVersion="15"
MinorVersion="0"
MajorBuildNumber="785"
MinorBuildNumber="6"
Version="V2_6"
xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<m:SyncFolderHierarchyResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:SyncFolderHierarchyResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:SyncState>H4sIAA==</m:SyncState>
<m:IncludesLastFolderInRange>true</m:IncludesLastFolderInRange>
<m:Changes>
<t:Create>
<t:Folder>
<t:FolderId Id="AAMkADM="
ChangeKey="AQAAABYA"/>
</t:Folder>
</t:Create>
<t:Create>
<t:Folder>
<t:FolderId Id="AAMkADMzM="
ChangeKey="AQAAABY"/>
</t:Folder>
</t:Create>
<t:Create>
<t:Folder>
<t:FolderId Id="AAMkAD/AAA="
ChangeKey="AQAAABYA"/>
</t:Folder>
</t:Create>
<t:Create>
<t:Folder>
<t:FolderId Id="AAMkADBh="
ChangeKey="AQAAABYA"/>
</t:Folder>
</t:Create>
...
</m:Changes>
</m:SyncFolderHierarchyResponseMessage>
</m:ResponseMessages>
</m:SyncFolderHierarchyResponse>
</s:Body>
</s:Envelope>
检索服务器上的新文件夹列表后,在 客户端上创建文件夹。
使用 EWS 获取自上次同步以来的更改
以下示例演示使用 SyncFolderHierarchy 操作获取根文件夹中文件夹更改列表的 XML 请求。 这也是 EWS 托管 API 在 检索根文件夹更改列表时发送的 XML 请求。 本示例将 SyncState 元素值设置为在上一响应中返回的值。 出于演示目的,此示例将 BaseShape 元素设置为 AllProperties 而不是 IdOnly 以显示返回的其他属性。 将 BaseShape 元素设置为 IdOnly 是 同步最佳做法。 SyncState 的值已缩短,以提高可读性。
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<t:RequestServerVersion Version="Exchange2013" />
</soap:Header>
<soap:Body>
<m:SyncFolderHierarchy>
<m:FolderShape>
<t:BaseShape>AllProperties</t:BaseShape>
</m:FolderShape>
<m:SyncFolderId>
<t:DistinguishedFolderId Id="root" />
</m:SyncFolderId>
<m:SyncState>H4sIAA==</m:SyncState>
</m:SyncFolderHierarchy>
</soap:Body>
</soap:Envelope>
以下示例显示了服务器在处理来自客户端的 SyncFolderHierarchy 操作 请求后返回的 XML 响应。 此响应指示更新了一个文件夹,创建了一个文件夹,并删除了一个文件夹。 为了提高可读性, SyncState 元素、 Id 属性和 ChangeKey 属性的值已缩短。
请记住,请求包含 AllPropertiesBaseShape。 这只是为了演示目的。 建议在生产环境中将 BaseShape 元素设置为 IdOnly 。
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="745" MinorBuildNumber="21" Version="V2_3"
xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<m:SyncFolderHierarchyResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:SyncFolderHierarchyResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:SyncState>H4sIAAA</m:SyncState>
<m:IncludesLastFolderInRange>true</m:IncludesLastFolderInRange>
<m:Changes>
<t:Update>
<t:Folder>
<t:FolderId Id="AAMkADM=" ChangeKey="AQAAABY" />
<t:ParentFolderId Id="AQMkADMzADI1==" ChangeKey="AQAAAA==" />
<t:FolderClass>IPF.Note</t:FolderClass>
<t:DisplayName>Meeting Notes</t:DisplayName>
<t:TotalCount>3</t:TotalCount>
<t:ChildFolderCount>0</t:ChildFolderCount>
<t:EffectiveRights>
<t:CreateAssociated>true</t:CreateAssociated>
<t:CreateContents>true</t:CreateContents>
<t:CreateHierarchy>true</t:CreateHierarchy>
<t:Delete>true</t:Delete>
<t:Modify>true</t:Modify>
<t:Read>true</t:Read>
<t:ViewPrivateItems>true</t:ViewPrivateItems>
</t:EffectiveRights>
<t:UnreadCount>0</t:UnreadCount>
</t:Folder>
</t:Update>
<t:Create>
<t:Folder>
<t:FolderId Id="AAMkADMzM=" ChangeKey="AQAAABYAA" />
<t:ParentFolderId Id="AQMkO67A==" ChangeKey="AQAAAA==" />
<t:FolderClass>IPF.Note</t:FolderClass>
<t:DisplayName>Schedules</t:DisplayName>
<t:TotalCount>0</t:TotalCount>
<t:ChildFolderCount>0</t:ChildFolderCount>
<t:EffectiveRights>
<t:CreateAssociated>true</t:CreateAssociated>
<t:CreateContents>true</t:CreateContents>
<t:CreateHierarchy>true</t:CreateHierarchy>
<t:Delete>true</t:Delete>
<t:Modify>true</t:Modify>
<t:Read>true</t:Read>
<t:ViewPrivateItems>true</t:ViewPrivateItems>
</t:EffectiveRights>
<t:UnreadCount>0</t:UnreadCount>
</t:Folder>
</t:Create>
<t:Delete>
<t:FolderId Id="AAMkAD/AAA=" ChangeKey="AQAAAA==" />
</t:Delete>
</m:Changes>
</m:SyncFolderHierarchyResponseMessage>
</m:ResponseMessages>
</m:SyncFolderHierarchyResponse>
</s:Body>
</s:Envelope>
更新客户端
如果使用 EWS 托管 API,在获取新文件夹或更改的文件夹列表后,请使用 Folder.Load 方法获取新项或已更改项的属性,将属性与本地值进行比较,并在客户端上更新或创建文件夹。
如果使用 EWS,请使用 GetFolder 操作 获取新文件夹或更改的文件夹的属性,并在客户端上更新或创建文件夹。