I’m in the process of building a web app to pull calendar events from Exchange 2003 and display them on a page. With some research and a lot of trial and error, I was able to put together bit and pieces of examples on the web and get most of it done. The only problem is that recurring events were not being pulled. It turns out that if a recurring event is schedule to recur ad infinitum, the WebDAV query will not retrieve the event unless a start date and end date is specified. Below is part of the code.
public void Authenticate(string authUri, string destinationUri, string username, string password)
{
// Create the web request body:
string body = string.Format(“destination={0}&username={1}&password={2}”, destinationUri, username, password);
byte[] bytes = Encoding.UTF8.GetBytes(body);
// Create the web request:
HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(authUri);
request.Method = “POST”;
request.ContentType = “application/x-www-form-urlencoded”;
request.CookieContainer = new CookieContainer();
request.ContentLength = bytes.Length;
// Create the web request content stream:
using (Stream stream = request.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);
stream.Close();
}
// Get the response & store the authentication cookies:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.Cookies.Count < 2)
throw new AuthenticationException(“Login failed. Is the login / password correct?”);
cookies = new CookieContainer();
foreach (Cookie myCookie in response.Cookies)
{
cookies.Add(myCookie);
}
response.Close();
}
public List<CalendarEvent> GetCalendar(string uri, DateTime startDate, DateTime endDate)
{
List<CalendarEvent> eventList = new List<CalendarEvent>();
HttpWebRequest request;
WebResponse response;
byte[] bytes;
// Note that deep traversals don’t work on public folders. In other words, if you
// need to dig deeper you’ll need to split your query into multiple requests.
string format =
@”<?xml version=””1.0″”?>” +
@”<D:searchrequest xmlns:D = “”DAV:””>” +
@”<D:sql>” +
@”SELECT “”urn:schemas:calendar:dtstart””, ” +
@”””urn:schemas:calendar:dtend””, ” +
@”””urn:schemas:calendar:location””, ” +
@”””urn:schemas:httpmail:subject””, ” +
@”””urn:schemas:httpmail:htmldescription””, ” +
@”””urn:schemas:httpmail:to””, ” +
@”””urn:schemas:calendar:organizer””, ” +
@”””DAV:parentname”” ” +
@”FROM ” +
@”Scope(‘SHALLOW TRAVERSAL OF “”{0}””‘) ” +
@”WHERE ” +
@”NOT “”urn:schemas:calendar:instancetype”” = 1 ” +
@”AND “”DAV:contentclass”” = ‘urn:content-classes:appointment’ ” +
@”AND “”urn:schemas:calendar:dtstart”” >= ‘{1}’ ” +
@”AND “”urn:schemas:calendar:dtend”” <= ‘{2}’ ” +
@”</D:sql>” +
@”</D:searchrequest>”;
string fullQuery = String.Format(format, uri, DateTime.Now.AddYears(-1).ToString(“yyyy/MM/dd”), DateTime.Now.AddYears(1).ToString(“yyyy/MM/dd”));
bytes = Encoding.UTF8.GetBytes(String.Format(fullQuery, uri, startDate, endDate));
// Use the authorization cookies we stored in the authentication method.
request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.CookieContainer = cookies;
request.Method = “SEARCH”;
request.ContentLength = bytes.Length;
request.ContentType = “text/xml”;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
}
response = (HttpWebResponse)request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
// Parse the XML response to find the data we need.
XmlDocument document = new XmlDocument();
document.Load(responseStream);
XmlNodeList subjectNodes = document.GetElementsByTagName(“e:subject”);
XmlNodeList startTimeNodes = document.GetElementsByTagName(“d:dtstart”);
XmlNodeList endTimeNodes = document.GetElementsByTagName(“d:dtend”);
XmlNodeList organizerNodes = document.GetElementsByTagName(“d:organizer”);
XmlNodeList bodyNodes = document.GetElementsByTagName(“e:htmldescription”);
XmlNodeList locationNodes = document.GetElementsByTagName(“d:location”);
XmlNodeList toNodes = document.GetElementsByTagName(“e:to”);
string bodyStart = “<!– Converted from text/rtf format –>\r\n\r\n”;
string bodyEnd = “\r\n\r\n</BODY”;
for (int index = 0; index < subjectNodes.Count; index++)
{
string subject = subjectNodes[index].InnerText;
string organizer = HttpContext.Current.Server.HtmlEncode(organizerNodes[index].InnerText.Replace(“\””, “”).Replace(“<“, “(“).Replace(“>”, “)”));
DateTime startTime = DateTime.Parse(startTimeNodes[index].InnerText);
DateTime endTime = DateTime.Parse(endTimeNodes[index].InnerText);
string body = bodyNodes[index].InnerText;
string location = locationNodes[index].InnerText;
//CalendarEvent is my custom class
CalendarEvent ev = new CalendarEvent();
ev.StartTime = startTime;
ev.EndTime = endTime;
ev.Subject = subject;
ev.Organizer = organizer;
ev.Body = body;
ev.Location = location;
eventList.Add(ev);
}
}
response.Close();
return eventList;
}