Migrating to Exchange Web Services, Part 2: Calendaring

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

Topic Last Modified: 2008-07-23

By Bob Bunn, Programming Writer

Applications that work with Microsoft Office Outlook and Microsoft Exchange Server typically extend one or more of the following features:

  • Messaging
  • Calendaring (including meetings and appointments)
  • Search
  • Contact management

In part one of this series, I talked about how you can use Exchange Web Services instead of CDOEX or WebDAV to handle messaging. In this article, I will compare the use of the legacy APIs and Exchange Web Services (EWS) for creating an appointment in your application.

Calendaring Overview

After messaging, calendaring tasks such as creating meeting invitations or appointments are the most common tasks for applications that work with Exchange. Creating a meeting invitation or appointment involves the following steps:

  1. Creating a Calendar object.
  2. Setting the meeting organizer.
  3. Setting the time zone.
  4. Setting the meeting date and time.
  5. Setting the subject.
  6. Setting the location.
  7. Inviting attendees.
  8. Including the body of the invitation.
  9. Connecting to the computer that is running Exchange 2007.
  10. Sending the invitation.
  11. Saving the meeting to the organizer's calendar.

The examples in this article show how the legacy APIs and Exchange Web Services handle creating an appointment.

Using CDOEX to Create an Appointment

Collaboration Data Objects for Exchange 2000 Server (CDOEX) is commonly used by applications to send e-mail messages and create calendar appointments. The following code example uses the CDOEX Appointment object to create and send an appointment.

Dim cnfg As CDO.Configuration
Dim appt As CDO.Appointment
Dim urlMBXCal As String

' URL to the calendar.
urlMBXCal = sUrlMBXCal

' Set the configuration information.
cnfg = New CDO.Configuration
With cnfg
' Set the meeting organizer.
.Fields(cdoSendEmailAddress) = "mindy@contoso.com"
' Set the time zone.
.Fields(cdoTimeZoneIDURN) = cdoPacific
.Fields.Update()
End With

' Create an appointment.
appt = New CDO.Appointment
With appt
' Associate the configuration with 
' this meeting instance.
.Configuration = cnfg

'Set the basic properties.
.StartTime = "1:00 PM 4/18/2008"
.EndTime = "2:00 PM 4/18/2008"
.Subject = "Office party planning"
.Location = "Floor 3, Room 311"
.TextBody = "Plan the party"
End With

' Add the required attendees.
appt.Attendees.Add("peter@contoso.com, aidan@contoso.com")

' Add the optional attendees.
With appt.Attendees.Add
.Address = "robert@contoso.com"
.Role = cdoOptionalParticipant
End With

' Send out the meeting requests to everyone who is added to the 
' Attendees collection in the previous lines of code..
appt.CreateRequest.Message.Send()

' Save the meeting to the organizer's calendar.
appt.DataSource.SaveToContainer(urlMBXCal)

' Clean up.
cnfg = Nothing
appt = Nothing

Note

The CDOEX libraries manage daylight saving time settings within the library instead of using the settings that are included in Exchange. When the daylight saving time rules change, for example when in 2007 the United States changed daylight saving time to start earlier and end later, the DLL must be updated for these changes to take effect.

Using WebDAV to Create an Appointment

The following code example uses WebDAV to create and send an appointment.

// Build the PROPPATCH XML request.
string requestXml = 
   "<?xml version=\"1.0\"?>" +
   "<g:propertyupdate" +
      "xmlns:g=\"DAV:\" " + 
      "xmlns:e=\"https://schemas.microsoft.com/exchange/\" " +
      "xmlns:mapi=\"https://schemas.microsoft.com/mapi/\" " +
      "xmlns:x=\"xml:\" " +
      "xmlns:cal=\"urn:schemas:calendar:\" " +
      "xmlns:dt=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\" " +
      "xmlns:header=\"urn:schemas:mailheader:\" " +
      "xmlns:mail=\"urn:schemas:httpmail:\">" +
      "<g:set>" +
         "<g:prop>" +
            "<g:contentclass>" +
"urn:content-classes:appointment" +
"</g:contentclass>" +
"<e:outlookmessageclass>" +
"IPM.Appointment" +
"</e:outlookmessageclass>" +
            "<mail:subject>Appointment Subject</mail:subject>" +
            "<mail:htmldescription>Let's meet here</mail:htmldescription>" +
            // Set the appointment item properties: location, time 
      // zone, and schedule.
            "<cal:location>meetappt Location</cal:location>" +
"<cal:dtstart dt:dt=\"dateTime.tz\">" +
"2008-05-18T23:00:00.000Z" +
"</cal:dtstart>" +
"<cal:dtend dt:dt=\"dateTime.tz\">" + 
"2008-05-18T23:30:00.000Z" +
"</cal:dtend>" +
            "<cal:instancetype dt:dt=\"int\">0</cal:instancetype>" +
            "<cal:busystatus>BUSY</cal:busystatus>" +
      "<cal:meetingstatus>CONFIRMED</cal:meetingstatus>" +
            "<cal:alldayevent dt:dt=\"boolean\">0</cal:alldayevent>" +
"<cal:responserequested dt:dt=\"boolean\">" +
"1" + 
"</cal:responserequested>" +
            // Set the reminder time (in seconds).
            "<cal:reminderoffset dt:dt=\"int\">900</cal:reminderoffset>" +
            "<header:to>someone@contoso.com</header:to>" +
            "<mapi:finvited dt:dt=\"boolean\">1</mapi:finvited>" +
         "</g:prop>" +
      "</g:set>" +
   "</g:propertyupdate>";
 
// Get a reference to the request stream.
HttpWebRequest request =(HttpWebRequest)WebRequest.Create("https://contoso.com/");
request.Credentials = new NetworkCredential("username","password", "domain");
request.ContentType = "text/xml";
request.Method = "POST";

// Send the request to the server to create the appointment.
using (Stream requestStream = request.GetRequestStream())
{
using (StreamWriter writer = new StreamWriter(requestStream))
      {
            // Write the message body to the request stream.
            writer.Write(requestXml);
            writer.Flush();
      }
}
 
// Get the response from the server.
HttpWebResponse response;
 
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException)
{
// Handle server communication error.
}
 
using (Stream responseStream = response.GetResponseStream())
{
// Parse the response.

As in the WebDAV example in part 1 of the series, you must manually build the XML requests and manage the transport.

Using Exchange Web Services to Create an Appointment

Using EWS to create an appointment is similar to using CDOEX for appointment creation because the same data elements are addressed.

The following code example shows how to create an appointment by using EWS. Note that the steps for setting the meeting organizer and setting the time zone are handled automatically based on context.

// Create the appointment.
CalendarItemType appointment = new CalendarItemType();

// Set the properties of the appointment.
appointment.Start = "2/14/2008 12:30:00PM";
appointment.StartSpecified = true;
appointment.End = "2/14/2008 1:30:00PM";
appointment.EndSpecified = true;
appointment.Subject = "Planning meeting";
appointment.Location = "Building 3, Room 311";
appointment.Body = new BodyType();
appointment.Body.BodyType1 = BodyTypeType.Text;
appointment.Body.Value = "Plan the department party.";

// Add required attendees.
appointment.RequiredAttendees = new AttendeeType[1];
appointment.RequiredAttendees[0] = new AttendeeType();
appointment.RequiredAttendees[0].Mailbox = new EmailAddressType();
appointment.RequiredAttendees[0].Mailbox.EmailAddress = "chris@contoso.com";

// Create the array of items that will contain the appointment.
NonEmptyArrayOfAllItemsType arrayOfItems = new NonEmptyArrayOfAllItemsType();
arrayOfItems.Items = new ItemType[1];

// Add the appointment to the array of items.
arrayOfItems.Items[0] = appointment;

// Create the CreateItem request.
CreateItemType createRequest = new CreateItemType();

// The SendMeetingInvitations attribute is required for calendar items.
createRequest.SendMeetingInvitations =
      CalendarItemCreateOrDeleteOperationType.SendToAllAndSaveCopy;
createRequest.SendMeetingInvitationsSpecified = true;

// Add the destination folder to the CreateItem request.
createRequest.SavedItemFolderId = new TargetFolderIdType();
createRequest.SavedItemFolderId.Item = folder;

// Add the items to the CreateItem request.
createRequest.Items = arrayOfItems;

// Create the appointment by calling the CreateItem method, which has
// the side effect of sending invitations to attendees.
CreateItemResponseType createResponse =
      serviceBinding.CreateItem(createRequest);

// Check the result.
if (createResponse.ResponseMessages.Items[0].ResponseClass !=
      ResponseClassType.Success)
{
      throw new Exception("EWSWrap.SendAppointment failed.");
}

In this example, a CalendarItemType object that represents the appointment is instantiated and passed to the CreateItem method.

Creating Appointment Recurrence

The following code examples show how appointment recurrence is handled in CDOEX and EWS.

You can use the IRecurrencePattern interface in CDOEX to set a recurring event, as shown in the following example.

Dim ObjRRule As IRecurrencePattern

'Frequency, for example cdoWeekly or cdoDaily.
ObjRRule.Frequency = cdoWeekly

'Interval, for example "2" for recurrence every 2 weeks.
ObjRRule.Interval = 2

'Pattern end date.
ObjRRule.PatternEndDate = "1/1/2008"

EWS uses the RecurrenceType class to set a recurring event. This class has properties that enable you to set the pattern and range types. Different pattern and range types are available, depending on the item type (CalendarItem, and so on).

The following EWS code example shows how the RelativeYearlyRecurrencePatternType and the EndDateRecurrenceRangeType classes are used.

CalendarItemType calendarItem = new CalendarItemType();

// Create a RelativeYearlyRecurrencePattern to indicate an 
// annual recurrence of this meeting on the third Monday in April.
RelativeYearlyRecurrencePatternType pattern =
      new RelativeYearlyRecurrencePatternType();
pattern.Month = MonthNamesType.April;
pattern.DayOfWeekIndex = DayOfWeekIndexType.Third;

// The DaysOfWeek property must be converted to a string because of 
// an overload of type names in the schema.
// The result is that the proxy generator produces a weak-string 
// type instead of a strong-enum type. You must supply a string in the
// correct DaysOfWeek format. Doing a ToString() on an 
// enumeration is the best way to do this.
pattern.DaysOfWeek = DayOfWeekType.Monday.ToString();

// Create a recurrence range that represents an appointment that ends on
// April 1, 2010. 
EndDateRecurrenceRangeType range = new EndDateRecurrenceRangeType();
range.EndDate = dtApril1st2010;

// Assemble the pieces to a Recurrence Type to form the 
// recurrence definition and assign it to the 
// Recurrence property on the calendar item.
RecurrenceType recurrenceInfo = new RecurrenceType();
recurrenceInfo.Item = pattern;
recurrenceInfo.Item1 = range;

calendarItem.Recurrence = recurrenceInfo;

But Wait, There's More

In part three of this series, I will provide examples that will show how to use Exchange Web Services to search the Exchange data store. And don't forget about the final article in the series, which will include fully functioning sample applications that illustrate all the scenarios described in the series.

Additional Information

For more information about migrating to EWS, see the following articles: