Creating iCalendar events with ASP.NET MVC

26. September 2009

From Wikipedia: iCalendar is a computer file format which allows internet users to send meeting requests and tasks to other internet users, via email, or sharing files with an .ics extension. Recipients of the iCalendar data file (with supporting software, such as an email client or calendar application) can respond to the sender easily or counter propose another meeting date/time.

My goal for this solution was to allow the users of my web application to add events to their Microsoft Outlook calendar. Using the iCalendar format makes the solution work with a lot of calendar applications.

So what do we need to make this work?

First I created a two classes. An Event class that contains information about the event and an iCalendar class that contains information about the calendar and a list of Events.

public class iCalendar
{
private const string DEFAULT_DATEFORMAT = "yyyyMMdd\\THHmmss\\Z";
private const string ALLDAY_DATEFORMAT = "yyyyMMdd";

public iCalendar()
{
this.Events = new List<Event>();
}
public List<Event> Events { get; set; }

public string Name { get; set; }
public string Description { get; set; }

//Helper methods to format the DateTime values.
//These are used from the MVC view.
public string GetTimeString(DateTime time)
{
return GetTimeString(time, false);
}
public string GetTimeString(DateTime time, bool allDay)
{
if (allDay)
return ";VALUE=DATE:" + time.ToUniversalTime().ToString(ALLDAY_DATEFORMAT);
else
return ":" + time.ToUniversalTime().ToString(DEFAULT_DATEFORMAT);
}
}

public class Event
{
public DateTime StartTime { get; set; }
public DateTime EndTime {get; set; }

public string Title { get; set; }
public string Location { get; set; }
public string Description { get; set; }
public string HtmlDescription { get; set; }

public bool AllDay { get; set; }
public bool Reminder { get; set; }

//A unique identifier for the event.
//If it's not set we return a new Guid value.
public string UID
{
get
{
if (string.IsNullOrEmpty(this.uid))
return Guid.NewGuid().ToString();
else
return this.uid;
}
set { this.uid = value; }
}
private string uid;
}

As you can see these classes are simple property containers without any real logic. To save space i removed some logic that returned default values if a property was not set. Similar to the UID property.

The View

Now we almost have our full implementation. All we need is a ASP.NET MVC View that renders the iCalendar data.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<iCalendar>"%>BEGIN:VCALENDAR
PRODID:-//jpalm.se//iCalendar example with ASP.NET MVC//EN
VERSION:2.0<%if (Model.Events.Count > 1){%>
X-WR-CALNAME:<%=Model.Name%>
X-WR-CALDESC:<%=Model.Description%>
CALSCALE:GREGORIAN
METHOD:PUBLISH<%}%><%foreach(var evnt in Model.Events){%>
X-MS-OLK-FORCEINSPECTOROPEN:TRUE
BEGIN:VEVENT
DTSTART<%=Model.GetTimeString(evnt.StartTime,evnt.AllDay)%>
DTEND<%=Model.GetTimeString(evnt.EndTime,evnt.AllDay)%>
LOCATION:<%=evnt.Location%>
TRANSP:OPAQUE
SEQUENCE:0
UID:<%=evnt.UID%>
DTSTAMP<%=Model.GetTimeString(evnt.StartTime)%>
CREATED<%=Model.GetTimeString(DateTime.Now)%>
LAST-MODIFIED<%=Model.GetTimeString(DateTime.Now)%>
DESCRIPTION:<%=evnt.Description%>
X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//E
N"
>\n<HTML>\n<HEAD>\n<TITLE></TITLE>\n</HEAD>\n<BODY><%=evnt.HtmlDescription%></BODY>\n</HTML>
SUMMARY:<%=evnt.Title%><%if(evnt.Reminder){%>
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Reminder
PRIORITY:5
END:VALARM<%}%>
END:VEVENT<%}%>
END:VCALENDAR

The X-?? fields are extensions to the iCalendar standard that works with Microsoft Outlook.

Okay, so what do we have here? A strongly typed view based on our iCalendar object. As you can see the inline server tags are not on their own lines. This is because we don’t want any extra line breaks in our output.

Microsoft Outlook behaves a bit differently depending on whether the iCalendar file contains one or several events. If there’s only one event Outlook will prompt the user with a ‘New appointment’-dialog that will be populated with the data from the file. All the user has to do is press save and the event is saved the user’s default calendar. If there are several events in the file Outlook will add a new calendar and all the events are displayed in that. This is why we only set a calendar name and description if the Model.Events.Count is larger then 1.

Other than that we don’t do anything funky. All the fields are defined in the iCalendar format.

So, last step. How do we use this?
public ActionResult Calendar()
{
var icalendar = new iCalendar();
icalendar.Events.Add(new Event
{
StartTime = DateTime.Now.AddHours(1),
EndTime = DateTime.Now.AddHours(2),
Title = "iCalendar blog post",
Description = "Write a blog post about using iCalendar in ASP.NET MVC",
Location= "@ Home"
});

//The file name to display in the Open/Save-file dialog.
string filename = icalendar.Events[0].Title;
//IE want's you to url encode the file name. Other browsers don't like this.
if (Request.UserAgent.ToLower().Contains("msie"))
filename = Server.UrlEncode(filename).Replace("+", " ");

//Set a content type
this.Response.ContentType = "text/calendar";
//Make the browser display the Open/Save-file dialog.
this.Response.AddHeader("Content-disposition", "attachment; filename=\"" + filename + ".ics\"");

//Render the view
return View("iCalendar", icalendar);
}

You probably should wrap the file name and header set up into a new ActionResult based class and then use that instead of setting this directly in the action method.

If the user presses a link that executes the Action above a save file dialog will appear and if Microsoft Outlook is installed the Create Appointment-dialog will display when the file is opened.

Save_Dialog Outlook_Dialog

And that’s how I added iCalendar support with ASP.NET MVC.

ASP.NET MVC ,

Comments

9/27/2009 4:49:12 PM #
Pingback from scriptsrss.com

jPalm | Creating iCalendar events with ASP.NET MVC Scripts Rss
2/5/2010 12:13:10 AM #
For every disciplined effort there is a multiple reward.
2/14/2010 12:43:00 PM #
To waken interest and kindle enthusiasm is the sure way to teach easily and successfully.
2/17/2010 5:13:27 PM #
Hello, I was researching the web  and I ran into your site. Keep up the awesome work.
2/23/2010 4:25:39 AM #
Hey everybody. Interesting topic for a blog. I have been searching the Internet for fun and came upon your website. Great post. Thanks a lot for sharing your knowledge! It is good to know that some people still put in an effort into handling their websites. I'll be sure to look in from time to time.
2/27/2010 5:23:37 PM #
Hi
I found your site through search at google.  Your article very useful for me, maybe for other people too.  Big Thanks

Regards
Orie
3/1/2010 11:11:52 PM #
Hello I am so delighted I found your blog, I really found you by mistake, while I was looking on Yahoo for something else, Anyways I am here now and would just like to say thanks for a tremendous post and a all round entertaining blog (I also love the theme/design), I don’t have time to read it all at the moment but I have bookmarked it and also added your RSS feeds, so when I have time I will be back to read more, Please do keep up the great work.
3/2/2010 6:54:30 AM #
Each friend represents a world in us, a world possibly not born until they arrive, and it's only by this meeting that a new world is born.
3/2/2010 11:33:21 AM #
I wasn't sure where to ask this but I would like to include your site to one of my directories. Please contact me at your convience because I only list webistes with the webmasters consent - thank you.
3/2/2010 9:37:54 PM #
Please let me know if you're looking for a writer for your website. You have some good content and I think I would be a good asset.
3/3/2010 5:50:53 AM #
Do you mind if I quote you on my blog if I link back to this page?
3/3/2010 9:13:51 AM #
Interesting article. I'm looking for more information on this and will surely keep checking back on this site. Thanks.
3/3/2010 3:05:26 PM #
Hi First time hopped here on jPalm | Creating iCalendar events with ASP.NET MVC your site, founde on Bing. hikurangi Send me news to ineedachopjob@gmail.com
3/4/2010 6:46:15 AM #
I like watching movies online, it is way easier than going to the theaters.
3/5/2010 11:29:47 AM #
Thanks for taking this opportunity to talk about this, I feel strongly about it and I benefit from learning about this subject. If possible, as you gain data, please update this blog with new information. I have found it extremely useful.
3/6/2010 11:33:03 AM #
Do have some sort of email system where I can get your blog posts emailed to me?
3/6/2010 1:09:06 PM #
Thanks for taking this opportunity to talk about this, I feel strongly about it and I benefit from learning about this subject. If possible, as you gain data, please update this blog with new information. I have found it extremely useful.
3/7/2010 12:47:11 AM #
I've stopped by here a couple times and it seems like your post get more informative every time. Keep it up I enjoy reading them.
3/7/2010 10:10:15 PM #
Thanks for sharing this excellent submit, i really adore your weblog, but i've some problem i dont know whether it's my side problem or on your site? some words from the submit on your blog have charactor encoding issue, yes i use auto detecting, can u pls appear into this problem a bit?
3/9/2010 2:38:50 AM #
Hello, I have browsed most of your posts. This post is probably where I got the most useful information for my research. Thanks for posting, maybe we can see more on this. Are you aware of any other websites on this subject
3/9/2010 6:46:28 PM #
Hello, I can’t recognise how to include your internet site in my rss reader. Will  you Aid in me, please
3/9/2010 9:02:53 PM #
Do you know which cell phone services allow tethering?

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Clicky Web Analytics