更新约会会使其更改为EWS 1.1中的会议

时间:2011-11-25 23:41:56

标签: exchange-server exchangewebservices

这是我正在尝试做的事情:

  • 在两个日期之间获取用户日历上的所有项目
  • 更新某些商品的LocationSubject

我收到了以下项目:

FindItemsResults<Appointment> findResults = calendar.FindAppointments(new CalendarView(startDate, endDate));

此查询正常。但每当我调用Update来保存项目时,我都会遇到异常:

Microsoft.Exchange.WebServices.Data.ServiceResponseException: One or more recipients are invalid.

即使我收到异常,该项目也会保存并更改为IsMeeting设置为true!现在更新的项目是与组织者等的会议......这实际上是对我来说数据损坏。

这是代码。它并不复杂。我只是通过更改LocationSubject来测试它,两者都会导致问题。

Appointment a = Appointment.Bind(_service, new ItemId(id));
a.Location = newLocation
a.Update(ConflictResolutionMode.AlwaysOverwrite);

我错过了一些概念或什么?这似乎是一个非常令人震惊的问题。

FWIW,这是针对Office 365服务器的EWS 1.1。

4 个答案:

答案 0 :(得分:15)

我在这个问题的帮助下弄明白了:

Exchange Appointment Types

关键是需要在第二个参数中设置Update标志的情况下调用SendInvitationsOrCancellationsMode.SendToNone方法。

像这样:

a.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);

答案 1 :(得分:5)

因此,当您永远不想向其他与会者发送约会更新时,tig的答案就有效。但是,要正确回答这个问题,您实际上需要加载与会者状态。

默认情况下,它会尝试向与会者发送约会更新,但是您的约会对象没有加载与会者状态,因此正在爆炸。执行绑定时,应加载与会者属性。您也应该加载组织器以覆盖另一个边缘情况:

  • AppointmentSchema.RequiredAttendees
  • AppointmentSchema.OptionalAttendees
  • AppointmentSchema.Resources
  • AppointmentSchema.Organizer

如果您要进行向与会者发送更新的更新,则会填充与会者。

然而,你需要担心的是另一个边缘案例。如果您预约时没有添加任何与会者(仅限组织者),那么EWS可能仍会抱怨并抛出此错误。它实际上适用于某些州的约会,但在其他州则失败。

所以最完整的解决方案是:

的组合
  1. 加载与会者状态。
  2. 检查与会者状态以查看是否有除组织者之外的任何与会者(取决于创建约会的方式,组织者可能会或可能不会出现在RequiredAttendees集合中)。如果没有则必须使用SendInvitationsOrCancellationsMode.SendToNone。
  3. 所以完整的样本看起来像是:

    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;
    }
    

答案 2 :(得分:1)

回答这个问题

  

“即使我收到异常,该项目也会保存并更改为   让IsMeeting设置为true!现在更新的项目是一个会议   组织者等......这对我来说实际上是数据损坏。“

Microsoft文档以小字体形式说明“会议请求只是一个约会对象。您可以通过向约会添加所需的与会者,可选的与会者或资源,将约会转换为会议请求“ - 如此处所见 http://msdn.microsoft.com/en-us/library/office/dd633641%28v=exchg.80%29.aspx

换句话说,只要您有任何与会者,Exchange就会自动将其转换为会议。

答案 3 :(得分:-1)

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;
        }