Freigeben über


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("https://{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

  • Anonymous
    June 12, 2006

    WebDAV Samples Index
    &amp;nbsp;
    Listed below are links to my WebDAV samples.&amp;nbsp; If you have questions...
  • Anonymous
    June 12, 2006
    Many times when scheduling appointments in Exchange, especially when you are already using HTTP requests...
  • Anonymous
    July 27, 2006
    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/";
               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);
  • Anonymous
    July 28, 2006
    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...
  • Anonymous
    July 30, 2006
    thanks a lot. My problem is solved :)