我要做的是:
- 获取用户日历上两个日期之间的所有项目
- 更新
Location
或Subject
我得到的项目与:
FindItemsResults<Appointment> findResults = calendar.FindAppointments(new CalendarView(startDate, endDate));
这个查询工作正常。但是每当我调用Update来保存项目时,我都会得到一个异常:
Microsoft.Exchange.WebServices.Data.ServiceResponseException: One or more recipients are invalid.
即使我得到一个异常,该项目被保存并被更改为将IsMeeting
设置为true!现在更新的项目是与组织者的会议等等……对我来说,这实际上是数据损坏。
下面是代码。没有比这更复杂的了。我已经通过更改Location
或Subject
进行了测试,两者都会导致问题。
Appointment a = Appointment.Bind(_service, new ItemId(id));
a.Location = newLocation
a.Update(ConflictResolutionMode.AlwaysOverwrite);
我错过了什么概念还是什么?这似乎是一个相当严重的问题。
哎呀,这是EWS 1.1针对Office 365服务器
我从这个问题中找到了答案:
Exchange Appointment Types
关键是Update
方法需要在第二个参数中设置SendInvitationsOrCancellationsMode.SendToNone
标志时调用。
:
a.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);
所以,当您永远不想向其他与会者发送约会更新时,tig的答案就有效了。然而,要正确回答这个问题,实际上需要加载与会者状态。
默认情况下,它正在尝试向与会者发送约会更新,但是您的约会对象没有加载与会者状态,因此爆炸。当您执行绑定时,您应该加载与会者属性。您可能还应该加载组织者,以覆盖另一种边缘情况:
- AppointmentSchema。RequiredAttendees
- AppointmentSchema。OptionalAttendees
- AppointmentSchema。资源
- AppointmentSchema。组织者
如果你想做一个向与会者发送更新的更新,这将使与会者填充。
然而,还有另一个你需要担心的边缘情况。如果您的约会没有添加与会者(只有组织者),那么EWS可能仍然会抱怨并抛出此错误。在某些州,它实际上对约会有效,但在其他州则失败。
所以最完整的解决方案是:
- 加载与会者状态。
- 检查与会者状态,以查看除组织者之外是否还有其他与会者(取决于创建约会的方式,组织者可能出现也可能不出现在RequiredAttendees集合中)。如果没有,那么你必须使用sendinvitationsorcancellationmode . sendtonone。
所以完整的样本看起来像这样:
Appointment a = Appointment.Bind(_service, new ItemId(id), new PropertySet(AppointmentSchema.RequiredAttendees, AppointmentSchema.OptionalAttendees, AppointmentSchema.Resources, AppointmentSchema.Organizer));
a.Location = newLocation
// Check if the appointment has attendees other than the organizer. The organizer may
// or may not appear in the required attendees list.
if (HasNoOtherAttendee(a.Organizer.Address, a.RequiredAttendees) &&
(a.OptionalAttendees.Count == 0) && (a.Resources.Count == 0))
{
a.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);
}
else
{
// We have other attendees in the appointment, so we can use SendToAllAndSaveCopy so
// they will see the update.
a.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToAllAndSaveCopy);
}
bool HasNoOtherAttendee(string email, AttendeeCollection attendees)
{
bool emptyOrOnlyMe = true;
foreach (var a in attendees)
{
if (!string.Equals(email, a.Address, StringComparison.OrdinalIgnoreCase))
{
emptyOrOnlyMe = false;
break;
}
}
return emptyOrOnlyMe;
}
要回答这个问题
"即使我得到一个异常,项目被保存并被更改为把IsMeeting设为true!现在更新的项目是一个会议组织者等等……对我来说,这实际上是数据损坏。"
微软文档中以小字说明:"会议请求只是一个有与会者的约会。您可以通过向约会"添加必需的与会者、可选的与会者或资源来将约会转换为会议请求,如下所示http://msdn.microsoft.com/en-us/library/office/dd633641%28v=exchg.80%29.aspx
换句话说,只要您有任何与会者,Exchange将自动将其转换为会议。
public static bool UpdateAppointment(ExchangeCredential credentials,
ItemId appointmentId, string newLocation, string newSubject,
DateTime startTime,
DateTime endTime)
{
ExchangeService service = GetExchangeService(credentials);
try
{
Appointment appt = Appointment.Bind(service, appointmentId,
new PropertySet(BasePropertySet.IdOnly, AppointmentSchema.Start,
AppointmentSchema.ReminderDueBy, AppointmentSchema.End, AppointmentSchema.StartTimeZone,
AppointmentSchema.TimeZone));
appt.Location = newLocation;
appt.Start = startTime;
appt.End = endTime;
appt.Subject = newSubject;
// very important! you must load the new timeZone
appt.StartTimeZone = TimeZoneInfo.Local;
//appt.Body.Text = newBody; //if needed
appt.Update(ConflictResolutionMode.AlwaysOverwrite);
}
catch (Exception ex)
{
throw ex;
}
return true;
}