在C#中创建iCal文件

76
我正在寻找一种在C# (ASP.Net) 中生成iCalendar文件(*.ics)的好方法。我已经找到了一些资源,但是它们中缺少的一件事情是对quoted-printable字段的支持——即带有回车和换行符的字段。
例如,如果description字段没有正确编码,只有第一行会显示,并可能破坏*.ics文件中其余信息。
我正在寻找能够生成*.ics文件的现有类和/或能够生成quoted-printable字段的类。

8
尽管这个问题发生在很久以前,但我想指出,引用可打印字段并不是iCalendar标准(vCalendar 2.0)的一部分。它们是vCalendar标准(vCalendar 1.0)的一部分,而该标准现在很少使用(如果有的话)。 iCalendar有自己的数据转义方法,比引用可打印更清洁,更容易解释。 - Doug
9个回答

73

我使用 DDay.Ical,这是一款很好的工具。

它能够打开一个ical文件,并将数据以漂亮的对象模型呈现。虽然它标注为beta版本,但对于我们来说它已经非常好用了。

2016年11月更新

此库已被弃用,不过已由其他开发者接手并作为iCal.NET重新发布。

有关发布的说明:rianjs.net/2016/07/dday-ical-is-now-ical-net

GitHub源代码:github.com/rianjs/ical.net


12

我发现最简单的方法是使用微格式标记你的HTML。

如果您想生成iCalendar文件,那么您可以使用hCalendar微格式,然后包括一个指向“添加到日历”的链接,该链接指向:

http://feeds.technorati.com/events/[包括http://在内的页面完整URL]

然后Technorati页面会解析您的页面,提取hCalendar信息并将iCalendar文件发送给客户端。


3
这种方法是由NerdDinner.com使用,看起来效果不错。话虽如此,我还是要赞一下DDay.iCal(尽管我有偏见):) - Doug
1
我不喜欢这种方法的原因是 Technorati 可能会更改其规格甚至关闭服务。不过这是个好主意。 - Gabriel Espinoza

3

我编写了一个shim函数来处理这个问题。它基本上是兼容的 - 唯一的问题是第一行只有74个字符而不是75个(74是为了处理后续行上的空格)...

 Private Function RFC2445TextField(ByVal LongText As String) As String

     LongText = LongText.Replace("\", "\\")
     LongText = LongText.Replace(";", "\;")
     LongText = LongText.Replace(",", "\,")

     Dim sBuilder As New StringBuilder
     Dim charArray() As Char = LongText.ToCharArray

     For i = 1 To charArray.Length
         sBuilder.Append(charArray(i - 1))
         If i Mod 74 = 0 Then sBuilder.Append(vbCrLf & " ")
     Next

     Return sBuilder.ToString

 End Function

我在我们的ICS订阅中使用这个来作为摘要和描述。只需提前加上字段并将其输入到该行中(例如,LongText =“SUMMARY:事件标题”)。 只要设置缓存时间足够长,它就不会太耗费资源。


受你的代码启发,我进行了重写(虽然使用了C#),其中解析是按块而不是逐个字符进行的。可以在相关问题中查看:http://stackoverflow.com/a/27164955/914512 - reexmonkey

2

我需要一个关于自定义时区的示例。下面是一个片段,展示了如何在ics中设置时区(并在asp.net中将其发送到浏览器)。

//set a couple of variables for demo purposes
DateTime IcsDateStart = DateTime.Now.AddDays(2);
DateTime IcsDateEnd = IcsDateStart.AddMinutes(90);
string IcsSummary = "ASP.Net demo snippet";
string IcsLocation = "Amsterdam (Netherlands)";
string IcsDescription = @"This snippes show you how to create a calendar item file (.ics) in ASP.NET.\nMay it be useful for you.";
string IcsFileName = "MyCalendarFile";

//create a new stringbuilder instance
StringBuilder sb = new StringBuilder();

//begin the calendar item
sb.AppendLine("BEGIN:VCALENDAR");
sb.AppendLine("VERSION:2.0");
sb.AppendLine("PRODID:stackoverflow.com");
sb.AppendLine("CALSCALE:GREGORIAN");
sb.AppendLine("METHOD:PUBLISH");

//create a custom time zone if needed, TZID to be used in the event itself
sb.AppendLine("BEGIN:VTIMEZONE");
sb.AppendLine("TZID:Europe/Amsterdam");
sb.AppendLine("BEGIN:STANDARD");
sb.AppendLine("TZOFFSETTO:+0100");
sb.AppendLine("TZOFFSETFROM:+0100");
sb.AppendLine("END:STANDARD");
sb.AppendLine("END:VTIMEZONE");

//add the event
sb.AppendLine("BEGIN:VEVENT");

//with a time zone specified
sb.AppendLine("DTSTART;TZID=Europe/Amsterdam:" + IcsDateStart.ToString("yyyyMMddTHHmm00"));
sb.AppendLine("DTEND;TZID=Europe/Amsterdam:" + IcsDateEnd.ToString("yyyyMMddTHHmm00"));

//or without a time zone
//sb.AppendLine("DTSTART:" + IcsDateStart.ToString("yyyyMMddTHHmm00"));
//sb.AppendLine("DTEND:" + IcsDateEnd.ToString("yyyyMMddTHHmm00"));

//contents of the calendar item
sb.AppendLine("SUMMARY:" + IcsSummary + "");
sb.AppendLine("LOCATION:" + IcsLocation + "");
sb.AppendLine("DESCRIPTION:" + IcsDescription + "");
sb.AppendLine("PRIORITY:3");
sb.AppendLine("END:VEVENT");

//close calendar item
sb.AppendLine("END:VCALENDAR");

//create a string from the stringbuilder
string CalendarItemAsString = sb.ToString();

//send the ics file to the browser
Response.ClearHeaders();
Response.Clear();
Response.Buffer = true;
Response.ContentType = "text/calendar";
Response.AddHeader("content-length", CalendarItemAsString.Length.ToString());
Response.AddHeader("content-disposition", "attachment; filename=\"" + IcsFileName + ".ics\"");
Response.Write(CalendarItemAsString);
Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();

2
(iCal 2.0)和quoted-printable不兼容。
在(vCal 1.0)中,quoted-printable经常用于表示不可打印字符,例如换行符(=0D=0A)。默认的vCal编码是7位,因此有时需要使用quoted-printable来表示非ASCII字符(您可以覆盖默认编码,但其他符合vCal标准的通信方不一定要理解它)。
在中,特殊字符使用转义表示,例如'\n'。默认编码为UTF-8,所有符合iCal标准的方必须支持它,这使得在iCal 2.0(以及vCard 3.0)中完全不需要使用quoted-printable。
您可能需要向客户/利益相关者澄清要求。似乎在vCal和iCal之间存在混淆。

感谢您强调UTF-8是默认编码。 - Andrea Antonangeli

1
根据RFC-2445,注释和描述字段是TEXT。测试字段的规则如下: [1] TEXT字段中的单行不得超过75个八位字节。 [2] 插入CRLF后跟空格来实现换行。 [3] 有几个字符必须进行编码,包括\(反斜杠);(分号),(逗号)和换行符。使用\(反斜杠)作为分隔符给出\ \; \, \n

示例:以下是具有格式化行断点的属性值的示例:

 DESCRIPTION:Meeting to provide technical review for "Phoenix"
   design.\n Happy Face Conference Room. Phoenix design team
   MUST attend this meeting.\n RSVP to team leader.

1

0

iCal 可能会很复杂,因此我建议使用库。DDay 是一个不错的免费解决方案。据我上次检查,它没有完全支持重复事件,但除此之外看起来非常好。一定要使用多个客户端测试日历。


0

我知道现在可能有点晚了,但这可能会帮助其他人。在我的情况下,我编写了一个带有.ics扩展名的文本文件。

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Calendly//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
DTSTAMP:20170509T164109Z
UID:your id-11273661
DTSTART:20170509T190000Z
DTEND:20170509T191500Z
CLASS:PRIVATE
DESCRIPTION:Event Name: 15 Minute Meeting\nDate & Time: 03:00pm - 03:15pm (
 Eastern Time - US & Canada) on Tuesday\, May 9\, 2017\n\nBest Phone Number
  To Reach You :: xxxxxxxxx\n\nany "link": https://wwww.yahoo.com\n\n
SUMMARY:15 Minute Meeting
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR

这对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接