Migrating to Exchange Web Services, Part 5: EWS Migration Sample

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-12-01

By Bob Bunn, Programming Writer

In the earlier installments in this series of migration articles, I described how you can use Exchange Web Services (EWS) to handle some tasks that are common to applications that work with Microsoft Exchange Server 2007.

Part five of this series includes a sample application that illustrates all the scenarios described in the series.

Overview of the EWS Migration Sample

The EWS Migration Sample uses Exchange Web Services to send messages, create an appointment, search the data store, and manage contact information from a user's Exchange 2007 mailbox.

The EWS Migration Sample includes the following components:

  • A messaging application that sends messages (including attachments), retrieves a list of messages in the Inbox, and subscribes to the mailbox.
  • A calendaring application that creates, accepts, and declines a meeting request or appointment.
  • A search application that searches through messages, contacts, and appointments.
  • A contact management application that creates a new contact and manages existing contacts.
  • A common wrapper assembly that includes common procedures that are shared by each application that is included in the sample.

Prerequisites

The following prerequisites are required before you can use the EWS Migration Sample:

  • Access to a computer that is running Exchange 2007 or Exchange 2007 Service Pack 1 (SP1) that has the Client Access and Mailbox server roles installed. The Exchange Web Services Migration Sample will retrieve mailbox data from Exchange 2007 or Exchange 2007 SP1.
  • A mail-enabled account that is located in the mailbox database on the Mailbox server. This account will be used to demonstrate the EWS Migration Sample. For more information about how to create this account, see How to Create a New Mail-Enabled User.
  • Access to a computer that is running Visual Studio 2005 or later versions to edit and build the applications.

Installing the EWS Migration Sample

Installing the EWS Migration Sample is easy. Download the sample from the Microsoft Download Center to a Windows XP or Windows Vista computer that has Visual Studio 2005 or a later version installed, and then double-click the EWSMigrationsSample.sln file to open the project in Visual Studio. If you are using Visual Studio 2008, you will have to follow the steps on the screen to convert the project.

For the applications to work correctly, you will have to modify the App.config file in each application folder. The following are the fields that you will have to modify:

  • UserName
  • Password
  • Domain
  • EWSUrlEndPoint

A Look Inside

Now that you know what the EWS Migration Sample application does, let's take a look at how it's built.

Directory Structure

The EWS Migration Sample directory structure consists of one top-level folder and three subfolders, as described in the following table.

Folder Description

EWSMigration\

The root folder of the application. Here you will find the .sln file to open the project in Visual Studio.

EWSMigration\EWSWrap\

Contains all the source files for the wrapper application.

EWSMigration\Calendaring\

Contains all the source files for the calendar application.

EWSMigration\ContactManagement\

Contains all the source files for the contact management application.

EWSMigration\Messaging\

Contains all the source files for the messaging application.

EWSMigration\Search\

Contains all the source files for the search application.

Now that you are familiar with the directory structure of the EWS Migration Sample, let's take a closer look at main components of each application. Each of the following sections will also outline what functions are used in the EWSWrap assembly.

Messaging Application

The following table lists and describes the functions that are included in the messaging application.

Function Description

btnSend_Click

Handles creating and sending a message. As part of creating the message, any attachment specified by the user is also handled.

btnGetMail_Click

Retrieves the active Inbox contents for the user.

lstContacts_DoubleClick

Handles double-clicking an item in the contacts list. This action will get the selected item’s details from the Exchange store, parse them, and then display the relevant data on the first tab. This also puts the sample into edit mode.

btnSub_Click and btnUnsub_Click

Initializes the subscriptions for the sample. This sends the message to the server that either begins or ends a “pull” subscription. The initial subscription request returns the subscription ID and a subscription watermark.

subTimer_Tick

Handles the winForms timer that is set up in the sample. On each tick of the timer, the sample will form a request asking whether anything has occurred since the last time asked. If something has occurred, the sample rebinds the list of Inbox contents. The subscription watermark is stored for use in the next call for new subscription events.

The following table lists and describes the EWSWrap methods for the messaging application.

Function Exchange Web Services call(s) Description

ListFolder()

FindItem ()

Forms a request to the Web service, setting the properties for those data items wanted—all, in this case—and what folders the user wants to search—for example, the user’s Inbox. Individual item properties that are brought back in the response to the request are specified by an ItemResponseShapeType. The request is sent, with the appropriate response type returned. The response is then unwound and checked for success, and then the payload information is extracted and presented to the user.

SendMail()

CreateItem ()

CreateAttachment ()

SendItem ()

Includes overloads for sending mail with or without attachments. The message is initialized with values from the input in the controls for To:, Cc:, subject, and so on. The message then flows through the following idiom:

  • The message is saved in the Sent Items folder.
  • The attachments are uploaded, and are attached to the message on the server, using identifiers returned from the save operation.
  • A request to send the message is sent to the server, which sends the message to its recipients.

Each operation is its own separate request and therefore has its own corresponding responses. These responses are checked at every step for success and exceptions are thrown if a failure occurs.

EstablishSubscription() and

CancelSubscription ()

Unsubscribe()

Used to establish and then revoke pull subscriptions with the server. There is also a more specialized EstablishInboxNewMailSubscription(), which is what the sample uses. When performing a subscription, the user must specify what folders are to be monitored, and what events are of interest. The latter function sets values for monitoring Inbox new mail events, and invokes the EstablishSubscription() routine. This routine has output parameters for which the calling sample has to track state. These values are used later in the act of retrieving events that may have occurred for a particular subscription. The idiom in pull subscriptions is to first establish the subscription, routinely poll the server for any events, and then cancel the subscription when it is no longer needed. There is also a time-out value, after which the subscription times out on the server.

GetSubscriptionEvents()

GetEvents ()

After the application has subscribed to the desired events, it uses a timer to periodically check for any new events. This is done by sending GetEventsType requests to the server, and then unwrapping the returned GetEventsResponse. If any events have occurred, the application clears its listing, and then issues a new request for Inbox contents. During each GetEvents() call, a bit of data, called a watermark, is returned in the response from the server. This watermark is cached, and then used in subsequent GetEvents() requests. When the subscription is canceled, the timer is stopped.

Calendaring Application

The following table lists and describes the functions that are included in the calendaring application.

Function Description

btnGetAppts_Click

Handles the retrieval of existing appointments and meeting invitations via interaction with the wrapper. The respective listViews are populated with the appropriate data columns. For appointments, different color coding is formatted for the user based on the status of the appointment.

btnAddAttendee_Click

Adds the textual attendee to the list of attendees for the meeting request. Note that no name resolution is performed.

lstAppointments_DoubleClick

Handles double-clicking an item in the appointment list. This action will get the selected item’s details from the Exchange store, parse them, and then display the relevant data on the first tab.

btnNew_Click

Clears any data in the controls on the first tab and disables the send button.

btnSend_Click

Crafts a calendar item from the user’s input and sends the request to create the item to the wrapper.

btnAccept_Click and btnDecline_Clic

Accepts or declines a highlighted item in the meeting invitations list. Upon the successful action, the listings are cleared and rebound to the active data in the store.

The following table lists and describes the EWSWrap methods for the calendaring application.

Function Exchange Web Services call(s) Description

ListCalendarItems ()

FindItem ()

Used to populate the listing for the user’s calendar. The listing is represented in the client application as a ListView control, populated with the string values for the Start Time, Organizer, and Subject properties of a CalendarItemType object. The corresponding wrapper routine FindItem() forms a request to the Web service, setting the properties for those data items wanted—all, in this case—and what folders the user wants to explore. Individual item properties that are brought back in the response to the request are specified by an ItemResponseShapeType. The request is sent, with the appropriate response type returned. The response is then unwound, checked for success, and then the payload information is extracted and presented to the user.

ListMeetingInvites ()

FindItem

Lists only mail messages that are of type meeting invite. This allows the sample to display the calendar items that directly correspond to the meeting invitation. A user can see that upon receiving a meeting invitation, a calendar entry is created in the user’s calendar, but is marked tentative and requires a response. Listing the invites separately is also convenient, because it enables the sample to respond to the meeting invitation message directly, as opposed to the calendar entry. Responding to the meeting invitation automatically updates the user’s calendar, and puts the meeting invitation message in the Deleted Items folder. The listing is represented in the client application as a ListView control populated with the string values for the TimeSent, From, and Subject properties of a MessageType object. The corresponding wrapper routine FindItem() forms a request to the Web service, sets the properties for the data items wanted, what folders to explore, and special filter strings to filter for meeting invitations. Individual item properties brought back in the response are specified by an ItemResponseShapeType. The request is sent with the appropriate response type returned. The response is then unwound and checked for success, and then the payload information is extracted and presented to the user.

SendAppointment ()

CreateItem ()

Sends the appointment. The appointment is initialized with values from the input in the controls for Subject, Location, Start and End times, and so on. A request to send the appointment is then sent to the server with the option SendToAllAndSaveCopy, which will send invitations to all the invitees. For simplification, all invitees are put under the required attendee list (there is also a list for optional attendees). The response is checked for success and exceptions are thrown if a failure occurs.

GetItem ()

GetItem ()

Gets the item from the Exchange store. This function is used to display the calendar entry on the sample form when the calendar listing is double-clicked, but can also be used to edit a particular item from the store. All items in the Exchange store have an itemID. Using this ID retrieval is a simple process. The consuming call must cast the return type to the specific type it has retrieved.

ResondToInvitation()

CreateItem ()

Used to either accept or decline a meeting invitation. When called, the accept or decline message is sent to the meeting organizer, and a calendar entry is either marked on the user’s calendar, or the tentative calendar entry that was present is removed.

Search Application

The following table lists and describes the functions that are included in the search application.

Function Description

bthSearch_Click

Handles the search button click. This function handles most of the interaction with the wrapper. Based on which elements are selected for search, the function, with help from the wrapper, crafts a search expression. The appropriate type of search expression is built, depending on the number of properties being searched for.

When the request is sent by using the wrapper, the returned results are parsed and displayed for the user. The listing is kept intentionally generic to accommodate the various object types that can be found.

The following table lists and describes the EWSWrap methods for the search application.

Function Exchange Web Services call(s) Description

FindItems()

FindItem ()

Generates the FindItem Web service request with the specified folders and search expression. The search expression is built in the calling routine with additional help from the wrapper.

For ease of use, the FindItem request is specified to return all the properties of the objects it locates. To better streamline a search operation, the request can be customized to return only specific properties.

Contact Management Application

The following table lists and describes the functions that are included in the contact management application.

Function Description

btnSend_Click

Handles creating or updating a contact item. If a user has previously double-clicked an item, this puts the sample into edit mode and the send will then do an update of the information. Otherwise, a new contact is created with the specified data.

btnGetContacts_Click

Retrieves the active contacts for the user.

lstContacts_DoubleClick

Handles double-clicking an item in the contacts list. This action will get the selected item’s details from the Exchange store, parse them, and then display the relevant data on the first tab. This also puts the sample into edit mode.

btnNew_Click

Clears any data in the controls on the first tab and puts the sample back into insert mode.

BuildChangeDescriptions

Builds the change description objects that are used in the wrapper’s update service. Exchange Web Services expects update information in a specific format. This routine supports the crafting of that update information for the fields that the sample supports. Code is provided for both indexed and non-indexed data.

The following table lists and describes the EWSWrap methods for the contact management application.

Function Exchange Web Services call(s) Description

ListAllContacts()

FindItem ()

Forms a request to the Web service, setting the properties for those data items wanted—all, in this case—and what folders the user wants to search, such as Contacts. Individual item properties that are brought back in the response to the request are specified by an ItemResponseShapeType. The request is sent, with the appropriate response type returned. The response is then unwound and checked for success, and then the payload information is extracted and presented to the user.

CreateContact()

CreateItem ()

Creates contacts. The contact is initialized with values from the input in the controls for Name, Company, E-mail, Address, and the like. A request to create the contact is then sent to the server. For simplification, the sample only uses a subset of the available properties for a contact. The response is checked for success and exceptions are thrown otherwise.

UpdateContact()

UpdateItem ()

Takes an itemId and changeKey together with a contact object and updates the contact in the Exchange store. The data that is updated is the same as that used to create a contact in this sample.

GetItem ()

GetItem ()

Gets the item from the Exchange store. All items in the Exchange store have an itemID associated with them. Using this ID retrieval is a simple process. The consuming call must cast the return type to the specific type (in this case a contactItem) that it has retrieved.

DeleteItem()

DeleteItem ()

Deletes the item—in this case, a contact—from the Exchange store. The ID, and in this case, the changeKey also, are used. Using these identifiers, the delete request is sent to the server.

Supportability

We strongly recommend that you perform thorough code and security reviews and testing before you deploy applications that are based on this sample in any production environment.