Exchange Web Services (EWS) Managed API – Part 1

I recently had to create data providers for both Microsoft Exchange 2007 and 2010.  Given that my existing providers for Exchange 2000/2003 made use of WebDAV, I took a look at the alternate options that are available as I was aware that WebDAV is not supported on Exchange 2010.

I’ve known about the existence of Exchange Web Services (EWS) for a while, but not had the opportunity to use it.  However, I was pleased to discover that during my absence from the world of Exchange development, Microsoft have released Exchange Web Services (EWS) Managed API.  So let us take a look at how simple it can make our code with an example where we get appointments from a calendar.

Initialising Connection

The first thing we need to do is open up our connection to our Microsoft Exchange Server (MXS).  In this example, I’m targeting 2010; you can see this from the ExchangeVersion enumeration provided in the constructor for the ExchangeService.

C#
ServicePointManager.ServerCertificateValidationCallback =
    delegate(object sender, X509Certificate certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

_exchange = new ExchangeService(ExchangeVersion.Exchange2010);
_exchange.Url = new Uri(Settings.ExchangeServerUrl + ExchangeService);

// Setting credentials is unnecessary when you connect from a computer that is
// logged on to the domain.
if (!string.IsNullOrEmpty(Settings.UserName))
{
    _exchange.Credentials = new WebCredentials(Settings.UserName,
        Settings.Password, Settings.DomainName);
}

The API does provide Autodiscover functionality, but in my test infrastructure I found I needed to be explicit. Aside from targeting MXS2010, you can target MSX2007 SP1 upwards. However, there are limitations in the 2007 implementation that meant in my scenario I had to ditch the use of the managed API and resort to WebDAV (more on this in Part 2).

For clarity, my settings and constant are as follows:

<mxs2010AppointmentProviderSettings
  exchangeServerUrl="https://192.168.1.150"
  domainName="contoso"
  userName="bobk"
  password="pass@word1" 
  isPublicFolderRoot="false"
  calendarPath="Year View Test/Calendar"
  slidingExpiration="00:15:00">
</mxs2010AppointmentProviderSettings>

C# Constant Definition
private const string ExchangeService = "/EWS/Exchange.asmx";

Finding the Calendar

Now that we are connected, we need to find the calendar that the appointments are stored in. The API relies upon the use of “Well Known Folder Names” or “Folder Ids”.  Having the FolderId for our calendar would be fantastic, but it is not something that is easily determined by the user that sets up your application, and it’s also my understanding that these Id’s can actually change over time for various reasons such as replication.  So our starting point is to use a WellKnownFolderName as our ‘root’ and then find the specific calendar that the user specifies (see above setting for calendarPath in this example).

C#
private static FolderId GetCalendarFolderId(
    ExchangeService exchange,
    string path,
    bool isPublicFolderRoot)
{
    string[] folderNames = path.Split(new string[] { "/" },
        StringSplitOptions.RemoveEmptyEntries);
    Folder parent = Folder.Bind(exchange, isPublicFolderRoot ?
        WellKnownFolderName.PublicFoldersRoot : WellKnownFolderName.MsgFolderRoot);

    foreach (string folder in folderNames)
    {
        SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(
            LogicalOperator.And,
            new SearchFilter.IsEqualTo(FolderSchema.DisplayName, folder));
        FindFoldersResults results = parent.FindFolders(searchFilter,
            new FolderView(1));

        if (results != null && results.TotalCount == 1)
        {
            parent = results.Folders[0];
        }
        else
        {
            parent = null; // Not found
            break;
        }
    }

    return parent != null ? parent.Id : null;
}

So you can see that we break the provided calendarPath into a string array that we can loop through; effectively walking down the hierarchy from the specified root node.  In the code you can see that our root node is either the public folder root, or the message folder root for the user.  When we have successfully traversed to the end, we end up with the target folder, and can return the FolderId for that child node.

(Clearly this is something that you would do as part of your initialisation process and store in your class.)

Searching the Calendar

Now that we have determined the FolderId for the calendar, we can retrieve appointments from it.  In the example below we have an AppointmentFilter class that defines a From and a To, and a boolean IsFullRecord that indicates whether we should be pulling back a full record (body in this case) rather than minimal.

C#
protected override IEnumerable<AppointmentEntity> GetEntitiesFromSource(
    AppointmentFilter filter)
{
    if (filter == null) { throw new ArgumentNullException("filter",
        "You must provide an allocated filter object"); }

    List<AppointmentEntity> appointments = new List<AppointmentEntity>();

    if (!_isInitialised) { InitialiseExchangeService(); }

    if (_isInitialised)
    {
        CalendarFolder folder = CalendarFolder.Bind(_exchange, _calendarFolderId);                
        DateTime dtStart = filter.From.ToUniversalTime();
        DateTime dtEnd = filter.To.ToUniversalTime();
        CalendarView calendarView = new CalendarView(dtStart, dtEnd);
        calendarView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties,
            ItemSchema.Subject, ItemSchema.Categories);

        FindItemsResults<Appointment> findResults = folder.FindAppointments(calendarView);

        // Load additional properties for the current batch of items.
        if (filter.IsFullRecord)
        {
            _exchange.LoadPropertiesForItems(findResults, new PropertySet(
                BasePropertySet.FirstClassProperties,
                ItemSchema.Subject, ItemSchema.Categories, ItemSchema.Body));
        }

        foreach (Appointment appointment in findResults.Items)
        {                    
            appointments.Add(ConvertAppointment(appointment, filter.IsFullRecord));                    
        }               
     }

    return appointments;
}

So you can see that we:-

  1. Bind to our CalendarFolder
  2. Create a CalendarView with our dates From and To – our filtering to narrow the scope.
  3. Set the PropertySet on the aforementioned CalendarView – basically, what properties we want returned to us.
  4. Execute the FindAppointments method on the calendar folder using our defined CalendarView. (It’s important to realise that this method does not return all properties for the items returned by the query – Exchange API-spotting)
  5. If we are looking for full record details, then we specify what those details are and explicitly load the additional properties on the returned results. 
  6. Finally we can loop through our results – in this case we convert them to our own objects and add to a list.

Conclusion

Well moving from WebDAV to this managed API is certainly an improvement from my perspective; smaller/neater code than via either WebDAV or EWS.  The current negatives are lack of documentation and examples, but given that it was only released at the end of last year: no big surprise.

However, I did discover some limitations and gotchas that we’ll cover in Part 2.

Print | posted on Wednesday, 19 May 2010 10:15 AM

Feedback

# re: Exchange Web Services (EWS) Managed API – Part 1

left by ecommerce website design at 14/10/2010 9:47 PM Gravatar
Your blog is incredible. I am delighted with it. Thanks for sharing with me.

# re: Exchange Web Services (EWS) Managed API – Part 1

left by dann at 12/11/2010 9:41 PM Gravatar
the main problem with Exchange Web Services I found, is that the item id is not constant. For example, if you move a email from mailbox to a public folder, it becomes a new emailid. How do you handle this problem?

# re: Exchange Web Services (EWS) Managed API – Part 1

left by Paul at 13/11/2010 8:45 AM Gravatar
Hi Dann

Yes, although I've not had to deal with email specifically in EWS, a general rule is that Ids are not guaranteed to stay the same (for various reasons).

So they should be used at runtime as a result of some other 'determination' process such as walking the tree from a known point, or looking for particular filter criteria.

Regards
Paul.

# re: Exchange Web Services (EWS) Managed API – Part 1

left by Raju at 8/07/2011 10:56 PM Gravatar
Hi

This article is more useful for me to understanding EWS.
Thank you...
-
Regards,
kasi

# re: Exchange Web Services (EWS) Managed API – Part 1

left by Andy at 12/09/2011 5:43 PM Gravatar
Hello,
thanks for this blog.
One question. Where can I find the calendarPath in Outlook?
Regards
Andy

# re: Exchange Web Services (EWS) Managed API – Part 1

left by Kumar at 15/11/2011 8:33 PM Gravatar
I am having similar requirement to migrate an application in exchange 2003 using webDAV to EWS Exchange2010. Is Exchange Web Services (EWS) Managed API can be used with C++ using ATL/COM

# re: Exchange Web Services (EWS) Managed API – Part 1

left by Clyde Bower at 24/11/2011 3:34 AM Gravatar
Any chance of getting the entire code (or VS project) that this code was built from?

# re: Exchange Web Services (EWS) Managed API – Part 1

left by BillJam at 21/03/2012 1:07 AM Gravatar
I didn't understand the need for the "Finding The Calendar" part. Couldn't you just use:

FolderId _calendarFolderId = Folder.Bind(service, WellKnownFolderName.Calendar).Id;

??

# re: Exchange Web Services (EWS) Managed API – Part 1

left by Paul at 21/03/2012 2:21 PM Gravatar
BiillJam

Because you can have multiple calendars...so doing what you suggest just gets the default...which may be what you require...but is not flexible enough for other situations.

# re: Exchange Web Services (EWS) Managed API – Part 1

left by mymacin at 28/09/2012 3:52 AM Gravatar
I want develop email client using EWS exchange web services. Does it requires any license from Microsoft.

# IT Support Los Angeles

left by IT Support Los Angeles at 6/12/2012 5:20 AM Gravatar
Keep me up great work.Thanks for sharing!

# re: Exchange Web Services (EWS) Managed API – Part 1

left by Modern Bridesmaid Dresses Cheap at 7/06/2013 5:37 PM Gravatar
I want develop email client using EWS exchange web services.
Title  
Name
Email (never displayed)
Url
Comments   
Please add 7 and 3 and type the answer here: