Visual Studio 2010!

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.
ADVERTISEMENT
ADVERTISEMENT

 

DevSource.com: Your Source for Visual Studio on Facebook
ADVERTISEMENT
Interacting with Google Calendar via .NET
By Tim Stevens

Rate This Article: Add This Article To:

Interacting with Google Calendar via .NET - ' Core Concepts '
( Page 3 of 3 )

Google Calendar Core Concepts

To do anything with your Google Calendar (or someone else's) you'll need an instance of CalendarService, the object through which most other operations are performed.

You'll also, of course, need to verify your existence, which can be done in a few different ways.

The easiest and, for most purposes, best way is to simply use the setUserCredentials method on an instance of CalendarService, passing in the username and password of the owner of the calendar.

Here's a quick example of how to get an instance, authenticate the user, then query the entries in the calendar.


CalendarService calendar = new CalendarService("DevSource Test App");
calendar.setUserCredentials("username", "pass");

EventQuery query = new EventQuery();
query.Uri = new 
    Uri("http://www.google.com/calendar/feeds/default/private/full");

EventFeed calFeed = calendar.Query(query);
foreach(EventEntry entry in calFeed.Entries)
{
    ...
}

The first two lines create the CalendarService instance and identify the application. The rest of the lines retrieve a feed of EventEntry objects via an instance of FeedQuery, which in this case is passed the standard URI for retrieving full access to a user's calendar. To retrieve a feed of a calendar's contents via this URI, you need to provide credentials separately. However, each calendar also has what's called a "magic cookie" URL that looks something like this:

http://www.google.com/calendar/feeds/testuser@gmail.com /private-1234567/basic

You can retrieve this URL by going to your Google Calendar account, accessing one of your calendar's settings, and then clicking on the XML icon next to the "Private Address" section. Using this URI allows you to access your calendar without authentication, should you be so inclined.

Once some instance of a feed has been retrieved (EventFeed in this case), its Entries provides access to a collection of individual EventEntry objects, each containing information about individual calendar events; the who, what, when, where, and why. To dig a little deeper into this interaction, let's work with a real-world example.

Easy Export

Google Calendar features a handy feature enabling it to import calendars in iCal or CSV format. This means you can go to MS Outlook, export a range of dates' worth of appointments, then load that into Google Calendar. The problem is, it's a two-step process, and you wind up with unneeded CSV files hanging around on your desktop. Wouldn't it be nicer if you could just click on a button?

The above is the simple UI created in Visual Studio that drives our test app. You type in your Google Calendar username and password, pick upper and lower bounds for the export dates, and then click the button. It'll do the export and import and display how many items were copied.

The first step is to talk to Outlook. That's achieved by including a reference to the Interop.Microsoft.Office.Core package (called "Microsoft Outlook 11.0 Object Library" under the COM tab in the "Add Reference" dialog under Visual Studio).

Using code like the following will provide access to all the calendar entries for the current Outlook user:

private Outlook.Items getOutlookItems()
{
    ApplicationClass outlook = new ApplicationClass();
    NameSpace nameSpace = outlook.GetNamespace("MAPI");
    MAPIFolder folder = 
        nameSpace.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
    return folder.Items;
}

The Outlook.Items collection contains all of the calendar entries. While we're not doing anything with them here, a good reader exercise would be to figure out the DASL intricacies to pull only the selected range of dates and improve performance. Instead, we'll rely on the Start and End properties of each AppointmentItem in the Outlook.Items collection.

First, though, we need to figure out what's already in the calendar, so that we don't add the same entry twice should you run this app twice. We do that by pulling all entries from the provided Google Calendar event, this time filtering on date, and adding them all to a hashTable with the subject of the calendar event acting as the key. The obvious shortcoming with this solution is that no two events within a selected date range that share a subject can be added to a calendar, but it'll work fine for this example.

private Hashtable getGoogleCalendarItems()
{
    Hashtable ret = new Hashtable();
    EventQuery query = new EventQuery();
    query.Uri = 
        new Uri(
        "http://www.google.com/calendar/feeds/default/private/full");
    query.StartTime = fromPicker.Value;
    query.EndTime = toPicker.Value;
    
    if(calendar == null)
        initCalendar();
    
    EventFeed calFeed = calendar.Query(query);
    while(calFeed.Entries.Count != 0)
    {
        foreach(EventEntry entry in calFeed.Entries)
        {
            if(!ret.Contains(entry.Title.Text))
    	    {
    	        ret.Add(entry.Title.Text, entry);
    	        ++googleCounter;
    	    }
        }
    	query.Uri = new Uri(calFeed.NextChunk);
    	calFeed = calendar.Query(query);
    }
    
    return ret;
}

First, we use an EventQuery like before; but this time we provide the start and end dates chosen on the front screen. A method initCalendar() initiates the global CalendarService instance, and then it is used to run the query. The resulting EventEntry instances are used in a foreach loop with each entry added to the Hashtable to be returned.

The final bit of complexity in this block of code is performing subsequent queries to get the rest of the results. By default, a query will return 25 entries. That can be changed via the NumberToReceive parameter to some arbitrarily large number, but it's a good idea to perform follow-up queries using the NextChunk URI to ensure that there aren't any more entries waiting to be retrieved.

Inserting the Results

Now that we have a collection of all the items from Outlook and a Hashtable containing the Google Calendar entries, it's time to find out which are missing from Google and do the insertions. By iterating over all the items retrieved from Outlook, then checking their dates against the user-entered values and their subjects against the Hashtable, it's easy enough to figure out which ones need inserting.

foreach(AppointmentItem item in outlookItems)
{
    if(item.Start > start && item.End < end)
    {
        if(!googleCalendarTable.Contains(item.Subject))
        {	
            ++counter;
            insertCalendarEntry(item);
        }
    }
}

Inside the insertCalendarEntry method is where the code to insert into GoogleCalendar resides:

private void insertCalendarEntry(AppointmentItem item)
{
    EventEntry newEntry = new EventEntry();
    
    newEntry.Authors.Add(new AtomPerson(AtomPersonType.Author, 
        item.Organizer.ToString()));
    newEntry.Title.Text = item.Subject;
    newEntry.Content.Content = item.Body;
    
    When times = new When();
    times.StartTime = item.Start;
    times.EndTime = item.End;
    
    newEntry.Times.Add(times);
    
    calendar.Insert(new Uri(
        "http://www.google.com/calendar/feeds/default/private/full"), 
    	newEntry);
}

An instance of EventEntry is created, and then populated with information retrieved from the Outlook AppointmentItem. Title corresponds to Subject, Content corresponds to Body, and so forth. The GData API uses a class called When to contain date ranges, so moving over the Outlook times requires creating an instance, setting its start and end values based on the AppointmentItem, then adding that to the EventEntry times.

Finally, the actual insertion happens via the global CalendarService instance, again using the default feed URI in this case, along with the EventEntry instance.

When running this code, you'll see a dialog like the above, asking you if it's ok for this application to access your e-mail information. You can click "Yes" once for each iteration, but it'll save a lot of clicking if you just click the "Allow access for" checkbox and click on Yes.

Wrap-Up

Obviously, the above example isn't perfect. It doesn't like multiple calendar events with the same subject, it'll get confused if you move an appointment around, and its logic could be made a bit more efficient. However, it shows how to query from and insert to a Google Calendar instance.

The only thing not covered yet is how to update an event, and that's only because it's so easy it doesn't need its own section: just retrieve your EventEntry via a query like those above, change whatever properties you want, and then call its update() method.

The Google Calendar Data API, and on a bigger scale the GData API, is easy to figure out and work with, providing a great opportunity for even new developers to come up with new and interesting tools that enable things like calendar collaboration, distributed scheduling of events, and calendar synchronization with virtually any device.



 
 
>>> More ASP and .Net Coding Techniques Articles          >>> More By Tim Stevens