Leveraging Exchange 2007 Web Services to Find Open Conference Rooms

Do you enjoy trying to find free conference rooms for meetings?  If you do, you’re probably a psycho who eats puppies.  I work at the headquarter campus of a large company with dozens upon dozens of buildings.  Apparently the sole function of my company is to hold meetings since it’s easier to find Hoffa’s body than a free conference room at 2 o’clock in the afternoon.  So what’s an architect with a free hour to do?  Build a solution!

I did NOT build a solution to free up more conference rooms.  That involves firing lots of people.  Not my call.  But, I DID build a solution to browse all the conference rooms of a particular building (or buildings) and show me the results all at once.  MS Exchange 2007 has a pretty nice web service API located at https://%5Bserver%5D/ews/exchange.asmx.


The service operation I was interested in was GetUserAvailability.  This guy takes in a list of users (or rooms if they are addressable) and a time window and tells if you the schedule for that user/room.


Note that I’m including the full solution package for download below, so I’ll only highlight a few code snippets here.  My user interface looks like this:


I take in a building number (or numbers), and have a calendar for picking which day you’re interested in.  I then have a time picker, and duration list.  Finally I have a ListVIew control to show the rooms that are free at the chosen time.  A quick quirk to note: so if I say show me rooms that are free from 10AM-11AM, someone isn’t technically free if they have a meeting that ends at 10 or starts at 11.  The endpoints of the other meeting overlap with the “free” time.  So, I had to add one second to the request time, and subtract one second from the end time to make this work right.  Why am I telling you this?  Because the shortest window that you can request via this API is 30 minutes.  So if you have meeting times of 30 minutes or less, my “second-subtraction” won’t work since the ACTUAL duration request is 28 minutes and 58 seconds.  This is why I hard code the duration window so that users can’t choose meetings that are less than an hour.  If you have a more clever way to solve this, feel free!

Before I get into the code that makes the magic happen, I want to highlight how I stored the building-to-room mapping.  I found no easy way to query “show me all conference rooms for a particular building” via any service operation, so, I built an XML configuration file to do this.  Inside the configuration file, I store the building number, the conference room “friendly” name, and the Exchange email address of the room.


I’ll use LINQ in code to load this XML file up and pull out only the rooms that the user requested.  On to the code!

I defined a “Rooms” class and a “RoomList” class which consists of a List of Rooms.  When you pass in a building number, the RoomList object yanks the rooms from the configuration file, and does LINQ query to filter the XML nodes and populate a list of rooms that match the building (or buildings) selected by the user.

class Room
    public string Name { get; set; }
    public string Email { get; set; }
    public string Bldg { get; set; }


class RoomList : List<Room>
    public void Load(string bldg)
        XDocument doc = XDocument.Load(HttpContext.Current.Server.MapPath("RoomMapping.xml"));

        var query = from XElem in doc.Descendants("room")
                    where bldg.Contains(XElem.Element("bldg").Value)
                    select new Room
                        Name = XElem.Element("name").Value,
                        Bldg = XElem.Element("bldg").Value,
                        Email = XElem.Element("email").Value

With this in place, we can populate the “Find Rooms” button action.  The full code is below, and reasonably commented.

protected void btnFindRooms_Click(object sender, EventArgs e)
        //note: meetings must be 1 hour or more

        //load up rooms from configuration file
        RoomList rooms = new RoomList();

        //create string list to hold free room #s
        List<string> freeRooms = new List<string>();

        //create service proxy
        ExchangeSvcWeb.ExchangeServiceBinding service =
            new ExchangeSvcWeb.ExchangeServiceBinding();

        //define credentials and target URL
        ICredentials c = CredentialCache.DefaultNetworkCredentials;
        service.Credentials = c;
        service.Url = "https://[SERVER]/ews/exchange.asmx";

        //create request object
        ExchangeSvcWeb.GetUserAvailabilityRequestType request =
            new ExchangeSvcWeb.GetUserAvailabilityRequestType();

        //add mailboxes to search from building/room mapping file
        ExchangeSvcWeb.MailboxData[] mailboxes = new ExchangeSvcWeb.MailboxData[rooms.Count];
        for (int i = 0; i < rooms.Count; i++)
            mailboxes[i] = new ExchangeSvcWeb.MailboxData();
            ExchangeSvcWeb.EmailAddress addr = new ExchangeSvcWeb.EmailAddress();
            addr.Address = rooms[i].Email;
            addr.Name = string.Empty;

            mailboxes[i].Email = addr;
        //add mailboxes to request
        request.MailboxDataArray = mailboxes;

        //Set TimeZone stuff
        request.TimeZone = new ExchangeSvcWeb.SerializableTimeZone();
        request.TimeZone.Bias = 480;
        request.TimeZone.StandardTime = new ExchangeSvcWeb.SerializableTimeZoneTime();
        request.TimeZone.StandardTime.Bias = 0;
        request.TimeZone.StandardTime.DayOfWeek = ExchangeSvcWeb.DayOfWeekType.Sunday.ToString();
        request.TimeZone.StandardTime.DayOrder = 1;
        request.TimeZone.StandardTime.Month = 11;
        request.TimeZone.StandardTime.Time = "02:00:00";
        request.TimeZone.DaylightTime = new ExchangeSvcWeb.SerializableTimeZoneTime();
        request.TimeZone.DaylightTime.Bias = -60;
        request.TimeZone.DaylightTime.DayOfWeek = ExchangeSvcWeb.DayOfWeekType.Sunday.ToString();
        request.TimeZone.DaylightTime.DayOrder = 2;
        request.TimeZone.DaylightTime.Month = 3;
        request.TimeZone.DaylightTime.Time = "02:00:00";

        //build string to expected format: 4/21/2010 04:00:00 PM
        string startString = calStartDate.SelectedDate.ToString("MM/dd/yyyy");
        startString += " " + ddlHour.SelectedValue + ":" + ddlMinute.SelectedValue + ":00 " + ddlTimeOfDay.SelectedValue;
        DateTime startDate = DateTime.Parse(startString);
        DateTime endDate = startDate.AddHours(Convert.ToInt32(ddlDuration.SelectedValue));

        //identify the time to compare if the user is free/busy
        ExchangeSvcWeb.Duration duration = new ExchangeSvcWeb.Duration();
        //add second to look for truly "free" time
        duration.StartTime = startDate.AddSeconds(1);
        //subtract second
        duration.EndTime = endDate.AddSeconds(-1);

        // Identify the options for comparing free/busy
        ExchangeSvcWeb.FreeBusyViewOptionsType viewOptions =
            new ExchangeSvcWeb.FreeBusyViewOptionsType();
        viewOptions.TimeWindow = duration;
        viewOptions.RequestedView = ExchangeSvcWeb.FreeBusyViewType.Detailed;
        viewOptions.RequestedViewSpecified = true;
        request.FreeBusyViewOptions = viewOptions;

        //call service!
        ExchangeSvcWeb.GetUserAvailabilityResponseType response =

        //loop through responses for EACH room
        for (int i = 0; i < response.FreeBusyResponseArray.Length; i++)
            //if there is a result for the room
            if (response.FreeBusyResponseArray[i].FreeBusyView.CalendarEventArray != null && response.FreeBusyResponseArray[i].FreeBusyView.CalendarEventArray.Length > 0)
                //** conflicts exist
            else  //room is free!
                freeRooms.Add("(" +rooms[i].Bldg + ") " + rooms[i].Name);


        //show list view
        lblResults.Visible = true;

        //bind to room list
        lvAvailableRooms.DataSource = freeRooms;


Once all that’s in place, I can run the app, search one or multiple buildings (by separating with a space) and see all the rooms that are free at that particular time.


I figure that this will save me about 14 seconds per day, so I should pay back my effort to build it some time this year.  Hopefully!  I’m 109% positive that some of you could take this and clean it up (by moving my “room list load” feature to the load event of the page, for example), so have at it.  You can grab the full source code here.


Author: Richard Seroter

Richard Seroter is Director of Developer Relations and Outbound Product Management at Google Cloud. He’s also an instructor at Pluralsight, a frequent public speaker, the author of multiple books on software design and development, and a former InfoQ.com editor plus former 12-time Microsoft MVP for cloud. As Director of Developer Relations and Outbound Product Management, Richard leads an organization of Google Cloud developer advocates, engineers, platform builders, and outbound product managers that help customers find success in their cloud journey. Richard maintains a regularly updated blog on topics of architecture and solution design and can be found on Twitter as @rseroter.

4 thoughts

  1. hi,
    Im trying to put put together a similar requirement, i have setup a meeting request in a room and when i try to use getuseravailability on the room or even on the attendee email addresses i always get response.FreeBusyResponseArray[i].FreeBusyView.CalendarEventArray as NULL

    Why is this happening.? Please help

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.