重复周期模式和 EWS
了解 Exchange 中的重复周期模式和定期系列。
定期系列是根据定义的模式重复的约会或会议。 定期序列可以有特定数量的出现,也可以无限期重复。 此外,定期序列可能具有不符合其余事件模式的异常,并且可能具有已从模式中删除的异常。 可以使用 EWS 托管 API 和 EWS 来处理定期系列及其关联的日历项。
定期日历项
所有日历项分为以下四个类别之一:
非定期日历项
定期主控服务器
序列中的出现次数
序列中修改的匹配项,称为异常
在本文中,我们将介绍属于定期系列的三种类型的日历项。
了解如何在 Exchange 服务器上实现定期系列会很有帮助。 服务器在日历中只创建一个实际项目(称为定期主控形状),而不是为定期系列中的每个事件创建单独的不同项。 定期主数据库的格式与非定期约会非常相似,并添加了重复模式信息。 然后,服务器使用称为扩展的过程,根据重复模式生成事件,以响应客户端对约会信息的请求。 这些生成的事件不会永久存储在服务器上。 了解这一点很重要,因为搜索日历项的方式决定了你收到的信息以及是否发生扩展。
定期模式
使扩展成为可能的定期序列的关键部分是重复模式。 定期模式在定期主数据库上找到,并描述了一组基于定期主节点的日期和时间计算出现次数的条件。
表 1. 可用定期模式
EWS 托管 API 类 | EWS 元素 | 示例 |
---|---|---|
Recurrence.DailyPattern |
DailyRecurrence |
每天重复一次。 每隔一天重复一次。 |
Recurrence.MonthlyPattern |
AbsoluteMonthlyRecurrence |
每月第十天重复一次。 在每月的第二十一天每隔一个月重复一次。 |
Recurrence.RelativeMonthlyPattern |
RelativeMonthlyRecurrence |
在每个月的第二个星期二重复。 每三个月在每月的第三个星期四重复一次。 |
Recurrence.RelativeYearlyPattern |
RelativeYearlyRecurrence |
在每年 8 月的第一个星期一重复。 |
Recurrence.WeeklyPattern |
WeeklyRecurrence |
每周一重复一次。 每星期二和星期四重复一次。 |
Recurrence.YearlyPattern |
AbsoluteYearlyRecurrence |
每年 9 月 1 日重复。 |
定期模式的另一个重要信息是定期结束时间。 这可以表示为一定数量的出现次数、结束日期或没有结束。
表 2. 定期系列末尾的选项
EWS 托管 API 方法/属性 | EWS 元素 | 说明 |
---|---|---|
Recurrence.NumberOfOccurrences |
NumberedRecurrence |
此属性或元素的值指定出现次数。 |
Recurrence.EndDate |
EndDateRecurrence |
序列中的最后一个匹配项位于此属性或元素指定的日期或之前。 |
Recurrence.HasEnd Recurrence.NeverEnds |
NoEndRecurrence |
该系列没有终点。 |
展开视图与非扩展视图
在 EWS 托管 API (中使用 FindAppointments 方法或使用 EWS 中的 CalendarView 元素的 FindItem 操作) 调用扩展过程。 这会从结果集中隐藏定期主约会,而是显示该定期系列的扩展视图。 结果集中包含属于日历视图参数的定期主控形状的 和 异常。 相反,在 EWS 托管 API (中使用 FindItems 方法或在 EWS) 中使用 IndexedPageItemView 或 FractionalPageItemView 元素的 FindItem 操作,不会调用扩展过程,并且不包括出现和异常。 让我们看一个比较这两种方法的示例。
表 3. 用于查找约会的方法和操作
EWS 托管的 API 方法 | EWS 操作 | 扩展系列? | 结果中包含的项 |
---|---|---|---|
ExchangeService.FindAppointments |
使用 CalendarView 元素执行 FindItem 操作 |
是 |
非定期约会、定期系列单次出现以及定期系列异常 |
ExchangeService.FindItems |
使用 IndexedPageItemView 元素或 FractionalPageItemView 元素的 FindItem操作 |
否 |
非定期约会和定期主约会 |
萨迪刚刚签下她的儿子去游泳队。 球队从7月2日开始,每周三上午8:30练习,最后一次练习是在8月6日。 不想忘记练习,萨迪在日历上增加了一个定期约会来提醒她。
表 4. 萨迪的定期约会
“约会”域 | 值 |
---|---|
主题 |
游泳队练习 |
开始 |
2014 年 7 月 2 日上午 8:30 |
End |
2014 年 7 月 2 日上午 10:00 |
复发 |
每周三 |
上次出现次数 |
2014 年 8 月 6 日上午 8:30 |
快速查看日历后,团队将总共有六个做法。 但是,日历中没有六个不同的约会项。 相反,只有一个代表序列的定期主约会。
现在,让我们看看在萨迪的日历上查找在 7 月内发生的约会。 下面的代码示例使用 Exchange 托管 API 中的 FindItems 方法生成 Sadie 日历的非扩展视图。
PropertySet propSet = new PropertySet(AppointmentSchema.Subject,
AppointmentSchema.Location,
AppointmentSchema.Start,
AppointmentSchema.End,
AppointmentSchema.AppointmentType);
#region FindItems + ItemView method
ItemView itemView = new ItemView(100);
itemView.PropertySet = propSet;
List<SearchFilter> filterList = new List<SearchFilter>();
// Find appointments that start after midnight on July 1, 2014.
SearchFilter.IsGreaterThan startFilter = new SearchFilter.IsGreaterThan(AppointmentSchema.Start,
new DateTime(2014, 7, 1));
// Find appointments that end before midnight on July 31, 2014
SearchFilter.IsLessThan endFilter = new SearchFilter.IsLessThan(AppointmentSchema.End,
new DateTime(2014, 7, 31));
filterList.Add(startFilter);
filterList.Add(endFilter);
SearchFilter.SearchFilterCollection calendarFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, filterList);
// This results in a call to EWS.
FindItemsResults<Item> results = service.FindItems(WellKnownFolderName.Calendar, calendarFilter, itemView);
foreach(Item appt in results.Items)
{
Console.WriteLine(appt.Subject);
}
该代码将生成以下具有 IndexedPageItemView 元素的 FindItem操作请求。
<?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="Exchange2007_SP1" />
<t:TimeZoneContext>
<t:TimeZoneDefinition Id="Pacific Standard Time" />
</t:TimeZoneContext>
</soap:Header>
<soap:Body>
<m:FindItem Traversal="Shallow">
<m:ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
<t:AdditionalProperties>
<t:FieldURI FieldURI="item:Subject" />
<t:FieldURI FieldURI="calendar:Location" />
<t:FieldURI FieldURI="calendar:Start" />
<t:FieldURI FieldURI="calendar:End" />
<t:FieldURI FieldURI="calendar:CalendarItemType" />
</t:AdditionalProperties>
</m:ItemShape>
<m:IndexedPageItemView MaxEntriesReturned="100" Offset="0" BasePoint="Beginning" />
<m:Restriction>
<t:And>
<t:IsGreaterThan>
<t:FieldURI FieldURI="calendar:Start" />
<t:FieldURIOrConstant>
<t:Constant Value="2014-07-01T07:00:00.000Z" />
</t:FieldURIOrConstant>
</t:IsGreaterThan>
<t:IsLessThan>
<t:FieldURI FieldURI="calendar:End" />
<t:FieldURIOrConstant>
<t:Constant Value="2014-07-31T07:00:00.000Z" />
</t:FieldURIOrConstant>
</t:IsLessThan>
</t:And>
</m:Restriction>
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="calendar" />
</m:ParentFolderIds>
</m:FindItem>
</soap:Body>
</soap:Envelope>
服务器的响应仅包括单个项,即定期主控形状,由 RecurrenceingMaster 的 CalendarItemType 元素值指示。 为了便于阅读,已缩短 ItemId 元素的值。
<?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="939" MinorBuildNumber="16" Version="V2_11"
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:FindItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:FindItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:RootFolder IndexedPagingOffset="1" TotalItemsInView="1" IncludesLastItemInRange="true">
<t:Items>
<t:CalendarItem>
<t:ItemId Id="AAMkADA5..." ChangeKey="DwAAABYA..." />
<t:Subject>Swim Team Practice</t:Subject>
<t:Start>2014-07-02T15:30:00Z</t:Start>
<t:End>2014-07-02T17:00:00Z</t:End>
<t:Location>Neighborhood Swimming Pool</t:Location>
<t:CalendarItemType>RecurringMaster</t:CalendarItemType>
</t:CalendarItem>
</t:Items>
</m:RootFolder>
</m:FindItemResponseMessage>
</m:ResponseMessages>
</m:FindItemResponse>
</s:Body>
</s:Envelope>
现在,让我们与展开的视图进行比较。 下面的代码示例使用 EWS 托管 API 中的 FindAppointments 方法创建 Sadie 日历的扩展视图。
PropertySet propSet = new PropertySet(AppointmentSchema.Subject,
AppointmentSchema.Location,
AppointmentSchema.Start,
AppointmentSchema.End,
AppointmentSchema.AppointmentType);
CalendarView calView = new CalendarView(new DateTime(2014, 7, 1),
new DateTime(2014, 7, 31));
calView.PropertySet = propSet;
FindItemsResults<Appointment> results = service.FindAppointments(WellKnownFolderName.Calendar, calView);
foreach(Appointment appt in results.Items)
{
Console.WriteLine(appt.Subject);
}
此代码使用 CalendarView 元素生成以下 FindItem 操作请求。
<?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="Exchange2007_SP1" />
<t:TimeZoneContext>
<t:TimeZoneDefinition Id="Pacific Standard Time" />
</t:TimeZoneContext>
</soap:Header>
<soap:Body>
<m:FindItem Traversal="Shallow">
<m:ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
<t:AdditionalProperties>
<t:FieldURI FieldURI="item:Subject" />
<t:FieldURI FieldURI="calendar:Location" />
<t:FieldURI FieldURI="calendar:Start" />
<t:FieldURI FieldURI="calendar:End" />
<t:FieldURI FieldURI="calendar:CalendarItemType" />
</t:AdditionalProperties>
</m:ItemShape>
<m:CalendarView StartDate="2014-07-01T07:00:00.000Z" EndDate="2014-07-31T07:00:00.000Z" />
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="calendar" />
</m:ParentFolderIds>
</m:FindItem>
</soap:Body>
</soap:Envelope>
这一次,服务器响应包括五个事件,7 月的每个星期三一次。 这些项目上的 CalendarItemType 元素都具有 Occurrence 值。 请注意,响应中不存在定期主控服务器。 为了提高可读性, 已缩短 ItemId 元素的值。
<?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="939" MinorBuildNumber="16" Version="V2_11"
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:FindItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:FindItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:RootFolder TotalItemsInView="5" IncludesLastItemInRange="true">
<t:Items>
<t:CalendarItem>
<t:ItemId Id="AAMkADA6..." ChangeKey="DwAAABYA..." />
<t:Subject>Swim Team Practice</t:Subject>
<t:Start>2014-07-02T15:30:00Z</t:Start>
<t:End>2014-07-02T17:00:00Z</t:End>
<t:Location>Neighborhood Swimming Pool</t:Location>
<t:CalendarItemType>Occurrence</t:CalendarItemType>
</t:CalendarItem>
<t:CalendarItem>
<t:ItemId Id="AAMkADA7..." ChangeKey="DwAAABYA..." />
<t:Subject>Swim Team Practice</t:Subject>
<t:Start>2014-07-09T15:30:00Z</t:Start>
<t:End>2014-07-09T17:00:00Z</t:End>
<t:Location>Neighborhood Swimming Pool</t:Location>
<t:CalendarItemType>Occurrence</t:CalendarItemType>
</t:CalendarItem>
<t:CalendarItem>
<t:ItemId Id="AAMkADA8..." ChangeKey="DwAAABYA..." />
<t:Subject>Swim Team Practice</t:Subject>
<t:Start>2014-07-16T15:30:00Z</t:Start>
<t:End>2014-07-16T17:00:00Z</t:End>
<t:Location>Neighborhood Swimming Pool</t:Location>
<t:CalendarItemType>Occurrence</t:CalendarItemType>
</t:CalendarItem>
<t:CalendarItem>
<t:ItemId Id="AAMkADA9..." ChangeKey="DwAAABYA..." />
<t:Subject>Swim Team Practice</t:Subject>
<t:Start>2014-07-23T15:30:00Z</t:Start>
<t:End>2014-07-23T17:00:00Z</t:End>
<t:Location>Neighborhood Swimming Pool</t:Location>
<t:CalendarItemType>Occurrence</t:CalendarItemType>
</t:CalendarItem>
<t:CalendarItem>
<t:ItemId Id="AAMkADAA..." ChangeKey="DwAAABYA..." />
<t:Subject>Swim Team Practice</t:Subject>
<t:Start>2014-07-30T15:30:00Z</t:Start>
<t:End>2014-07-30T17:00:00Z</t:End>
<t:Location>Neighborhood Swimming Pool</t:Location>
<t:CalendarItemType>Occurrence</t:CalendarItemType>
</t:CalendarItem>
</t:Items>
</m:RootFolder>
</m:FindItemResponseMessage>
</m:ResponseMessages>
</m:FindItemResponse>
</s:Body>
</s:Envelope>
拥有定期主控形状、事件或异常后,始终可以 检索其他相关项。 给定事件或异常,可以检索定期主控服务器,反之亦然。
使用定期日历项
使用与处理非定期日历项相同的方法和操作来处理定期系列。 区别在于,根据用于调用这些方法或操作的项,所执行的操作可以应用于整个系列,也可以应用于单个事件。 对定期主数据库执行的操作 将应用于系列中的所有事件,而 对单个事件或异常执行的操作 将仅适用于该事件或异常。