DAV: How To Search Calendar For Conflicts


Here is a WebDAV sample for searching a user’s calendar for conflicts.  Given a mailbox name and timeframe it will search for any appointments…


 






 


//************************************


// Get the contents of the calendar within a date range


// CREATED BY: mstehle


// CREATED ON: 6/9/06


//************************************


public string SearchCalendar(string mailboxName, DateTime start,


    DateTime end)


{


    // Build the Calendar folder URL


    string calFolderUrl = string.Format(“http://{0}/exchange/{1}/calendar/”,


        _server, mailboxName);


 


      // Build the SQL query.


      string strQuery;


      strQuery =  “<?xml version=\”1.0\”?>” +


                “<D:searchrequest xmlns:D = \”DAV:\”>” +


                “<D:sql>” +


                “SELECT \”DAV:displayname\” “ +


                “FROM scope(‘shallow traversal of \”” + calFolderUrl + “\”‘) “ +


                “WHERE \”DAV:isfolder\” = false “ +


                “AND (\”urn:schemas:calendar:dtstart\” &lt;= CAST(\””


                    + Utils.ConvertToISO8601(end) + “\” as ‘dateTime’)) “ +


                “AND (\”urn:schemas:calendar:dtend\” &gt;= CAST(\””


                    + Utils.ConvertToISO8601(start) + “\” as ‘dateTime’)) “ +


                “</D:sql>” +


                “</D:searchrequest>”;


 


    // DEBUG: Print out the SEARCH Query


    Debug.WriteLine(strQuery);


 


      // Create the HttpWebRequest object.


    System.Net.HttpWebRequest request =


        (System.Net.HttpWebRequest)HttpWebRequest.Create(calFolderUrl);


 


      // Create credentials from user name and password


      System.Net.CredentialCache creds = new CredentialCache();


    System.Uri folderUri = new Uri(calFolderUrl);


    System.Net.NetworkCredential netCred =


        new NetworkCredential(_userName, _password, _domain);


      creds.Add(folderUri, “Basic”, netCred);


 


      request.Credentials = creds.GetCredential(folderUri, “Basic”);


 


      // Specify the method.


      request.Method = “SEARCH”;


      request.ContentType = “text/xml”;


    request.Headers.Add(“translate”, “f”);


      request.KeepAlive = true;


      request.AllowAutoRedirect = false;


 


      // Encode the body using UTF-8.


      byte[] bytes = null;


      bytes = Encoding.UTF8.GetBytes((string)strQuery);


 


      // Set the content header length.  This must be


      // done before writing data to the request stream.


      request.ContentLength = bytes.Length;


      System.IO.Stream requestStream = request.GetRequestStream();


      requestStream.Write(bytes, 0, bytes.Length);


      requestStream.Close();


 


      // Send the SEARCH method request and get the


      // response from the server.


      System.Net.WebResponse response = (HttpWebResponse)request.GetResponse();


      System.IO.Stream responseStream = response.GetResponseStream();


 


    System.IO.StreamReader responseReader =


        new System.IO.StreamReader(responseStream);


    string strResponse = responseReader.ReadToEnd();


 


      // Clean up.


    responseReader.Close();


      responseStream.Close();


      response.Close();


 


    // DEBUG: Print out the response string


    Debug.WriteLine(strResponse);


 


    return strResponse;


}


 


In order to properly check for appointments within a given timeframe, we need to look for any appointment that begins before the end datetime and ends after the start datetime.


 


For example, if we are searching within a single day for a block of time between 2:00 PM and 3:00 PM for existing appointments.  The following appointments fall within that timeframe 10:00 AM – 4:00 PM, 2:15 PM – 2:45 PM, and 2:55 PM – 3:30 PM.  Therefore we can’t simply search for appointments whose start times are greater than the start times and end times are less than the end times.


 


…Like many I missed this logic the first time I tried to right this function.  This is a very useful query to use when checking real time availability of user…

Comments (5)

  1. WebDAV Samples Index

    &amp;nbsp;

    Listed below are links to my WebDAV samples.&amp;nbsp; If you have questions…

  2. Many times when scheduling appointments in Exchange, especially when you are already using HTTP requests…

  3. zille says:

    I am trying to query a calender folder to get the appointments with a specific data range but the exception arises that request is not right. I am not sure what is the problem with the request that i am making. can any one guide me i am posting the code:

    // Variables.

               System.Net.HttpWebRequest Request;

               System.Net.WebResponse Response;

               System.Net.CredentialCache MyCredentialCache;

               string strCalendarURI = "http://EUR-MSG-01/exchange/t-annaw/calendar/&quot;;

               string strUserName = "i-zilleh";

               string strPassword = "zill-786";

               string strDomain = "EUROPE";

               string strQuery = "";

               byte[] bytes = null;

               System.IO.Stream RequestStream;

               System.IO.Stream ResponseStream;

               System.Xml.XmlDocument ResponseXmlDoc;

               System.Xml.XmlNodeList SubjectNodeList;

               System.Xml.XmlNodeList LocationNodeList;

               System.Xml.XmlNodeList StartTimeNodeList;

               System.Xml.XmlNodeList EndTimeNodeList;

               System.Xml.XmlNodeList BusyStatusNodeList;

               System.Xml.XmlNodeList InstanceTypeNodeList;

               try

               {

                   // Build the SQL query.

                   strQuery = "<?xml version="1.0"?>"

                            + "<g:searchrequest xmlns:g="DAV:">"

                            + "<g:sql>SELECT "urn:schemas:calendar:location", "urn:schemas:httpmail:subject", "

                            + ""urn:schemas:calendar:dtstart", "urn:schemas:calendar:dtend", "

                            + ""urn:schemas:calendar:busystatus", "urn:schemas:calendar:instancetype" "

                            + "FROM Scope(‘SHALLOW TRAVERSAL OF "" + strCalendarURI + ""’) "

                            + "WHERE NOT "urn:schemas:calendar:instancetype" = 1 "

                            + "AND "DAV:contentclass" = ‘urn:content-classes:appointment’ "

                            + "AND "urn:schemas:calendar:dtstart" > ‘2006/07/18 00:00:00’ "

                             + "ORDER BY "urn:schemas:calendar:dtstart" ASC"

                            + "</g:sql></g:searchrequest>";

                   // Create a new CredentialCache object and fill it with the network

                   // credentials required to access the server.

                   MyCredentialCache = new System.Net.CredentialCache();

                   MyCredentialCache.Add(new System.Uri(strCalendarURI),

                      "NTLM",

                      new System.Net.NetworkCredential(strUserName, strPassword, strDomain)

                      );

                   // Create the HttpWebRequest object.

                   Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strCalendarURI);

                   // Add the network credentials to the request.

                   Request.Credentials = MyCredentialCache;

                   // Specify the method.

                   Request.Method = "SEARCH";

                   // Encode the body using UTF-8.

                   bytes = Encoding.UTF8.GetBytes((string)strQuery);

                   // Set the content header length.  This must be

                   // done before writing data to the request stream.

                   Request.ContentLength = bytes.Length;

                   // Get a reference to the request stream.

                   RequestStream = Request.GetRequestStream();

                   // Write the SQL query to the request stream.

                   RequestStream.Write(bytes, 0, bytes.Length);

                   // Close the Stream object to release the connection

                   // for further use.

                   RequestStream.Close();

                   // Set the content type header.

                   Request.ContentType = "text/xml";

                   // Send the SEARCH method request and get the

                   // response from the server.

                   Response = (HttpWebResponse)Request.GetResponse();

                   // Get the XML response stream.

                   ResponseStream = Response.GetResponseStream();

                   // Create the XmlDocument object from the XML response stream.

                   ResponseXmlDoc = new XmlDocument();

                   ResponseXmlDoc.Load(ResponseStream);

                   // Build a list of the urn:schemas:httpmail:subject XML nodes,

                   // corresponding to the calendar item subjects returned in the search request.

                   // The urn:schemas:httpmail: namespace is typically

                   // assigned the e: prefix in the XML response body.

                   SubjectNodeList = ResponseXmlDoc.GetElementsByTagName("e:subject");

                   // Build a list of the urn:schemas:calendar:location XML nodes,

                   // corresponding to the calendar item locations returned in the search request.

                   // The urn:schemas:calendar: namespace is typically

                   // assigned the d: prefix in the XML response body.

                   LocationNodeList = ResponseXmlDoc.GetElementsByTagName("d:location");

                   // Build a list of the urn:schemas:calendar:dtstart XML nodes,

                   // corresponding to the calendar item locations returned in the search request.

                   StartTimeNodeList = ResponseXmlDoc.GetElementsByTagName("d:dtstart");

                   // Build a list of the urn:schemas:calendar:dtend XML nodes,

                   // corresponding to the calendar item locations returned in the search request.

                   EndTimeNodeList = ResponseXmlDoc.GetElementsByTagName("d:dtend");

                   // Build a list of the urn:schemas:calendar:busystatus XML nodes,

                   // corresponding to the calendar item locations returned in the search request.

                   BusyStatusNodeList = ResponseXmlDoc.GetElementsByTagName("d:busystatus");

                   // Build a list of the urn:schemas:calendar:instancetype XML nodes,

                   // corresponding to the calendar item locations returned in the search request.

                   InstanceTypeNodeList = ResponseXmlDoc.GetElementsByTagName("d:instancetype");

                   // Loop through the returned calendar items (if any).

                   if (SubjectNodeList.Count > 0)

                   {

                       Console.WriteLine("Calendar items…");

                       for (int i = 0; i < SubjectNodeList.Count; i++)

                       {

                         

                               // Display the subject.

                               Console.WriteLine("  Subject:       " + SubjectNodeList[i].InnerText);

                               // Display the location.

                               Console.WriteLine("  Location:      " + LocationNodeList[i].InnerText);

                               // Display the start time.

                               Console.WriteLine("  Start time:    " + StartTimeNodeList[i].InnerText);

                               // Display the end time.

                               Console.WriteLine("  End time:      " + Convert.ToDateTime(EndTimeNodeList[i].InnerText));

                               // Display the busy status.

                               Console.WriteLine("  Busy status:   " + BusyStatusNodeList[i].InnerText);

                               // Display the instance type.

                               if (InstanceTypeNodeList[i].InnerText == "0")

                                   Console.WriteLine("  Instance type: 0-Single appointment");

                               else if (InstanceTypeNodeList[i].InnerText == "1")

                                   Console.WriteLine("  Instance type: 1-Master recurring appointment");

                               else if (InstanceTypeNodeList[i].InnerText == "2")

                                   Console.WriteLine("  Instance type: 2-Single instance, recurring appointment");

                               else if (InstanceTypeNodeList[i].InnerText == "3")

                                   Console.WriteLine("  Instance type: 3-Exception to a recurring appointment");

                               else

                                   Console.WriteLine("  Instance type: Unknown");

                               Console.WriteLine("");

                               Console.ReadLine();

                           }

                       }

                   

                   else

                   {

                       Console.WriteLine("No calendar items found …");

                     

                       

                   }

                 

                   // Clean up.

                   ResponseStream.Close();

                   Response.Close();

               }

               catch (Exception ex)

               {

                   // Catch any exceptions. Any error codes from the SEARCH

                   // method request on the server will be caught here, also.

                   Console.WriteLine(ex.Message);

  4. mstehle says:

    This is a common mistake if I’m reading your comment correctly…

    Make sure you use "&gt;" and "&lt;" instead of ">" or "<" because the angle brackets are reserved for XML tags.  See my request above…

  5. zille says:

    thanks a lot. My problem is solved 🙂