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\" <= CAST(\"" + Utils.ConvertToISO8601(end) + "\" as 'dateTime')) " + "AND (\"urn:schemas:calendar:dtend\" >= 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
&nbsp;
Listed below are links to my WebDAV samples.&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 ">" and "<" 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 :)