Using WebDAV to Get Calendar Items (Appointments) from Exchange in C#/ASP.Net

I'm a big believer in integration of pretty much everything. Not that big on mash ups (as most of them are terrible) but I believe that information should be easily used in various systems. That's part of the reason that I like Microsoft products now (during the 90s, I was on the other end of the spectrum though so I'm happy with the changes they've been making). I especially like Exchange because it is extremely easy to pull information from it for your own purposes.

In my instance, I had to create a personalized calendar that pulled information from exchange and displayed it on an intranet page. With the help of WebDAV, it took about 10 minutes to write (and since people only come here for the code, I figured I'd share):

        public static List<VCalendar> GetCalendarItems(string UserName, string Password, string Directory,string Server,DateTime StartDate,DateTime EndDate)
        {
            try
            {
                List<VCalendar> ReturnArray = new List<VCalendar>();
                NetworkCredential credentials = new NetworkCredential(UserName, Password);
                string uri = string.Format("http://{0}/exchange/{1}/calendar/", Server, Directory);

                string Query = "<?xml version=\"1.0\"?>"
                     + "<g:searchrequest xmlns:g=\"DAV:\">"
                     + "<g:sql>SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\", "
                     + "\"urn:schemas:httpmail:htmldescription\", "
                     + "\"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\", "
                     + "FROM Scope('SHALLOW TRAVERSAL OF \"" + uri + "\"') "
                     + "WHERE \"urn:schemas:calendar:dtstart\" &gt;= '" + StartDate.ToString("yyyy/MM/dd hh:mm:ss") + "' "
                     + "AND \"urn:schemas:calendar:dtstart\" &lt;= '" + EndDate.ToString("yyyy/MM/dd hh:mm:ss") + "' "
                     + "ORDER BY \"urn:schemas:calendar:dtstart\" ASC"
                     + "</g:sql></g:searchrequest>";
                byte[] contents = System.Text.Encoding.UTF8.GetBytes(Query);

 

                HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
                request.Credentials = credentials;
                request.Method = "SEARCH";
                request.ContentLength = contents.Length;
                request.ContentType = "text/xml";

                using (System.IO.Stream requestStream = request.GetRequestStream())
                    requestStream.Write(contents, 0, contents.Length);

                using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                    using (System.IO.Stream responseStream = response.GetResponseStream())
                    {
                        XmlDocument document = new XmlDocument();
                        document.Load(responseStream);
                        foreach (XmlElement element in document.GetElementsByTagName("a:prop"))
                        {
                            VCalendar Cal = new VCalendar();
                            if (element["e:htmldescription"] != null)
                            {
                                Cal.Description = element["e:htmldescription"].InnerText;
                            }
                            if (element["e:subject"] != null)
                            {
                                Cal.Subject = element["e:subject"].InnerText;
                            }
                            if (element["d:location"] != null)
                            {
                                Cal.Location = element["d:location"].InnerText;
                            }
                            if (element["d:dtstart"] != null)
                            {
                                Cal.StartTime = DateTime.Parse(element["d:dtstart"].InnerText);
                            }
                            if (element["d:dtend"] != null)
                            {
                                Cal.EndTime = DateTime.Parse(element["d:dtend"].InnerText);
                            }
                            ReturnArray.Add(Cal);
                        }
                    }
                }
                return ReturnArray;
            }
            catch
            {
                return new List<VCalendar>();
            }
        }

So let's talk about the code a bit. First off, it's using my VCalendar code from my utility library. Well actually it's using a slightly different version that contains a GethCalendar function. I'll talk about hCalendar items in a different post though... So beyond that, you'll notice that there is a large section that sets up the Query string object. That's the actual WebDAV query. It's very similar to SQL but you call fields based on the schemas that were set up (I'm using the urn:schemas:calendar schema the most in this bit of code). We also ask it to only give us items within the start and end dates (you'll notice I use &gt; and &lt;. The reason for this is pretty simple... It's XML that we're sending. XML+ > or < = bad...).

After the query itself we simply set up an HttpWebRequest object with the proper user name/password, content (in bytes), etc. We make the call to the exchange server and it returns to us a nice big chunk of XML in return. If you want to look through the structure of what it returns, go ahead (it's very basic). But the items themselves are located within a:prop objects. So we just get the list of those items and iterate through grabbing the information that we want. That's all there is to the code really. Anyway, I hope this helps someone out. So give it a try, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 11/7/2008 at 9:53 AM
Tags: , , ,
Categories: ASP.Net | C# | Web Design
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Getting a Users Contacts List from an Exchange Server

A request that recently popped up at work was the ability to use a person's contacts list from outlook when they were using a particular portion of the intranet site. Not that difficult to do actually. All that is required is a call using WebDAV to the exchange server and we have that user's contact's list. Actually there are a couple of ways to accomplish it but I found that to be the easiest. Anyway, as always I'm sure you're interested in the code:

public static System.Web.UI.WebControls.ListItemCollection GetContacts(string UserName,string Password,string Directory)

{
    System.Web.UI.WebControls.ListItemCollection ReturnArray = new System.Web.UI.WebControls.ListItemCollection();
    string server = "http:/ /ExchangeServer";
    NetworkCredential credentials = new NetworkCredential(UserName, Password);
    string uri = string.Format("{0}/exchange/{1}", server, credentials.UserName);
    byte[] contents = System.Text.Encoding.UTF8.GetBytes(string.Format(

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

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

            <g:sql>

                SELECT

                    ""urn:schemas:contacts:givenName"", ""urn:schemas:contacts:sn"",

                    ""urn:schemas:contacts:email1""

                FROM

                    Scope('SHALLOW TRAVERSAL OF ""{0}/exchange/{1}/contacts""')

            </g:sql>

        </g:searchrequest>",

      server, credentials.UserName));

 

    HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
    request.Credentials = credentials;
    request.Method = "SEARCH";
    request.ContentLength = contents.Length;
    request.ContentType = "text/xml";

    using (System.IO.Stream requestStream = request.GetRequestStream())
        requestStream.Write(contents, 0, contents.Length);

 

    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
    using (System.IO.Stream responseStream = response.GetResponseStream())
    {
        XmlDocument document = new XmlDocument();
        document.Load(responseStream);
        foreach (XmlElement element in document.GetElementsByTagName("a:prop"))
        {
            if (element["d:sn"] != null && element["d:givenName"] != null && element["d:email1"] != null)
            {
                System.Web.UI.WebControls.ListItem TempItem = new System.Web.UI.WebControls.ListItem();
                TempItem.Text = element["d:sn"].InnerText+", "+element["d:givenName"].InnerText;
                TempItem.Value = element["d:email1"].InnerText;
                ReturnArray.Add(TempItem);
            }
        }
    }
    return ReturnArray;
}

Note that this code is a modified version of the code you'll find here. All this call does, is makes a call doing WebDAV asking the exchange server to search the person's contacts directory and return an item's first name, last name, and email address. We can get a lot more information if needed, you can look at the urn:schemas:contacts namespace if you want something else. Once we have the information, it just creates a ListItemCollection and drops the items in there (I was using this in a drop down list). You can of course create your own Contacts class and put the info in there if you prefer. Anyway, use the code, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/24/2008 at 11:31 AM
Tags: , ,
Categories: ASP.Net | Web Design
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Creating Appointments (vCalendar) in C#, Interesting Interview, and AI

To be honest I used the code here and here to get started. And finding even those two items was rather painful. However manipulating an appointment on an exchange server is actually pretty easy once you get used to WebDAV. However finding the info to help you do just that is a little daunting. However I've been able to cobble together a class that can create an appointment/meeting and save it to a person's calendar, email that appointment to the various invitees, send out cancellations of that meeting, and also delete an appointment from someone's calendar. Note though that the code isn't finished:

Appointment.zip (3.52 kb)

You're going to have to modify the code a bit though to get it working (specifically edit any line that says http://exchangeserver to point to your own exchange server). Another issue is that the class isn't done yet. I'm currently working on a couple of other methods, the class isn't documented, etc. So I'll be sure to upload a finished version of this when I get a chance.

In other news, I'm sure if you read Gamasutra you've already read this interview. If you haven't read it yet, definitely do so. It's really interesting (at least to me considering I loved Dwarf Fortress). In fact the next game/engine that I'm creating pulls a lot of the design from it. The portion of the interview that I found most interesting was the world generation. Anyway, definitely read it.

Another article I suggest that you read is this one over at AIGameDev.com. It does a good job at highlighting some issues you should consider when designing the AI in your game. 

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 3/13/2008 at 3:51 PM
Tags: , , , ,
Categories: ASP.Net | C# | Game Programming | Web Design
Post Information: Permalink | Comments (4) | Post RSSRSS comment feed