Misleading documentation - Exchange meeting requests

Hello Exchange!

A few weeks ago I had the opportunity to work with on-premise Exchange Server 2013. Microsoft provides a powerful interface to manage Exchange mailboxes called EWS (Exchange Web Services). Unfortunately, communication between EWS and Exchange Server is based on heavy-weight SOAP messages. Instead of creating requests and parsing responses manually, I decided to use EWS Managed API. This is an open-source library, which wraps SOAP communication and provides API for .NET developers in more object-oriented manner.

Schedule a meeting

My task was to save information about meeting entered by organizer and (after successfully validation and data persistence) to send meeting request to all attendees. The first part was quite simple - show a form, bind data and save into database.

The second part of the task was more interesting. Before I started implementation I opened a EWS Managed API documentation and I found how to create and send a meeting request. The sample code looks so easy. It consists in three simple steps:

  • create an Appointment object representing a meeting
  • set meeting data using propper Appointment object’s properties (start date, location, attendees, etc.)
  • call Save method of an Appointment object
Appointment meeting = new Appointment(service);

meeting.Subject = "Team building exercise";
meeting.Body = "Let's learn to really work as a team and then have lunch!";
meeting.Start = DateTime.Now.AddDays(2);            
meeting.End = meeting.Start.AddHours(4);
meeting.Location = "Conference Room 12";
meeting.RequiredAttendees.Add("Jan.Kowalski@exchange.local");
meeting.OptionalAttendees.Add("Jan.Nowak@exchange.local");
meeting.ReminderMinutesBeforeStart = 60;

meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy);

Everything seemed to work fine. Meeting request was sent correctly and all participants received it. Unexpectedly, when I tried to accept or decline meeting request, I’ve got a following error message:

The action couldn't be completed. A conflicting change was made to the item on the server.

My helpful screenshot

Problem investigation

Firstly, I asked Google and Stack Overflow about this error. They said nothing - it didn’t bode well.

The next step was to check, if the client application makes appropriate calls to the Exchange Server. I used Fiddler to trace requests performed by EWS Managed API. There was nothing suspicious. I saw well-formed requests with valid SOAP messages in their bodies.

“If the client works good, there must be a server-side issue”, I said to myself. I made sure, that no one beside me was using the same Exchange Server. Then I created a meeting request manually - it worked fine. I verified Exchange Server settings and mailboxes permissions, but everything were set as it should be. I asked sys-admins to install the latest Cumulative Update for Exchange Server. Unfortunately, the problem remained unresolved.

I wasted a couple of hours and I went back to square one.

Time is my enemy

I looked at the documentation and I compared a body of the sample request from documentation and what I got using the same sample code.

<t:CalendarItem>
    <t:Subject>Team building exercise</t:Subject>
    <t:Body BodyType="HTML">Let's learn to really work as a team and then have lunch!</t:Body>
    <t:ReminderMinutesBeforeStart>60</t:ReminderMinutesBeforeStart>
    <t:Start>2013-09-21T16:00:00.000Z</t:Start>
    <t:End>2013-09-21T20:00:00.000Z</t:End>
    <t:Location>Conference Room 12</t:Location>
    <t:RequiredAttendees>
        ...
    </t:RequiredAttendees>
    <t:OptionalAttendees>
        ...
    </t:OptionalAttendees>
    <t:MeetingTimeZone TimeZoneName="Pacific Standard Time" />
</t:CalendarItem>

They were nearly identical except for the different time of start and end of the meeting. It’s obvious that they were different, because in the sample code the start time is set on current time (DateTime.Now). One thing was suspicious - the start and end time were set at full hour.

I set the start and end time manually on the exact point in time and sent it.

app.Start = new DateTime(year: 2016, month: 9, day: 30, hour: 19, minute: 0, second: 0);
app.End = new DateTime(year: 2016, month: 9, day: 30, hour: 20, minute: 0, second: 0);

All attendees received the meeting request. When I tried to accept or decline, finally Exchange set an attendee status correctly and notified a meeting organizer about it. Great!

To make investigation be completed, I performed an experiment. I set manually the start time using the value of miliseconds greater than 0.

app.Start = new DateTime(year: 2016, month: 9, day: 30, hour: 19, minute: 0, second: 0, millisecond: 1);

Result? After I tried to accept the meeting request, I saw the same error again!

The author of documentation had 1 out of 1000 probability for getting current time of 0 miliseconds. Coincidence? Is writer of documentation a lucky guy? ( ͡° ͜ʖ ͡°)

Lessons learned

  • If you write a documentation, please check twice that all of sample code snippets work correctly and get expected, repeatable results. Put a disclaimer whenever on some conditions examples may fail.
  • It is important to be vigilant if you work with a documentation of a new or unfamiliar technology. Write integration tests which cover basic use cases and edge cases. Such tests can prove correctness of a manual. Furthermore, one day your external API provider can make a change in a webservice functionality or you can update a library to the newest version. Those tests will help you quickly detect unexpected breaking changes in third-party technologies used by your application.
  • An error message should be helpful in troubleshooting. Show precise and well-formatted description of encountered problem. Furthermore, you can suggest steps to solve a problem. Avoid displaying meaningless (ex. “An error has occured”) or misleading error messages, which could only increase frustration of your users.
  • I encourage you to share solutions of such problems on the internet. You have nothing to loose, but you can save a lot of hours of other developers which will encounter similar problem.
  • Exchange Server, for some reason, doesn’t like overly punctual people. Bear in mind that Exchange accept time accurate to the second. You have to round milliseconds to the nearest second, unless Exchange may behave strange.

Stepping out of the shadow

First step

After a few months of hesitation, finally I’ve decided to start writing a blog. Why? There are many reasons that convinced me to make this decision:

  • Blogging boosts motivation to study and explore new technologies.

  • Teaching is the best way of learning. If you can explain something as easily as it is possible, it means that you understand it very well.

  • I want to keep my solutions of problems encountered in work and in my pet-projects in one place. Unfortunatelly, Stack Overflow is not a panacea for all problems. So many times I spent a lot of hours to solve various difficulties. Perhaps someone will be able to use my solution and save precious time. I believe that Dev-karma always comes back.

  • I would like to treat my blog as a tech-diary and watch my career progress and changes in time. Furthermore, I can verify my ideas, sharing my thoughts about software development with other people and providing an opportunity to comment on every blog-post. I think that constructive criticism is a good thing and personally I like read or hear well-reasoned opinions about my work. It almost always starts an interesting discussion.

Language choice

Why I decided to write in English?

  • I want to reach a wider audience and exchange experiences with developers from all over the world.

  • I think that English is a lingua franca in IT world. I read a lot of books and e-books in English version (Polish translations are terrible). I use documentations and specifications written in English. It’s often easier for me to express my thoughts about software engineering in English than in my native language.

  • Polish is primary language using in communication in the company I work for. This results from the fact that ITMAGINATION is a Polish company and most of employees are Poles. Those who are not, at the beginning they usually use English, but in the meantime they try to learn Polish (and they do it very well!). Of course, it is easier and faster to speak in native language, but I would like increase my English skills. Practice makes perfect.

Blogging platform

Out of all the blogging platforms I chose Jekyll. It is a static site generator, easy to configure and deploy. Jekyll doesn’t use database and can be hosted for free on GitHub Pages. Posts are created using Markdown syntax, which simplifies a process of text-formatting and allows me completely focus on content.

Further steps

I hope that this post is not the last. The first step is always the hardest, but I’ve made it. Now it’s high time to start blogging!

  • Page: 1 of 1