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() |
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() |
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:
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 () |
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() |
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 () |
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 () |
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 () |
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 () |
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() |
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() |
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() |
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() |
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() |
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 () |
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() |
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.
Additional Resources
For more information about how to create applications by using Exchange Web Services, see the following resources: