public class RssBase
{
// 常數設定
private const string TITLE = "MyMedia RSS";
private const string LINK = "https://www.example.com/";
private const string DESCRIPTION = "網站內容摘要";
private const string LANGUAGE = "zh-TW";
private const string COPYRIGHT = "Copyright 2024";
private const string GENERATOR = "MyMedia RSS Generator";
private const string IMAGE_URL = "https://www.example.com/logo.png";
private const string IMAGE_TITLE = "MyMedia";
private const string IMAGE_LINK = "https://www.example.com/";
private const string XMLNS_MEDIA = "https://search.yahoo.com/mrss/";
private const string XMLNS_DC = "https://purl.org/dc/elements/1.1/";
// 內部狀態
private XmlTextWriter _writer;
private bool _hasMedia;
private IList _items;
// 建構子
public RssBase(XmlTextWriter writer) : this(writer, false, null) { }
public RssBase(XmlTextWriter writer, bool hasMedia, IList items)
{
_writer = writer;
_hasMedia = hasMedia;
_items = items ?? new List();
}
// Item 資料模型
[Serializable]
public sealed class ItemInfo
{
public string ItemTitle { get; set; }
public string ItemLink { get; set; }
public string ItemDescription { get; set; }
public string ItemPubDate { get; set; } = DateTime.Now.ToString("R"); // RFC 1123
public string ItemAuthor { get; set; }
public string ItemGuid { get; set; }
// MediaRSS 欄位
public string MediaContentUrl { get; set; }
public string MediaTitle { get; set; }
public string MediaDescription { get; set; }
public string MediaThumbUrl { get; set; }
public string MediaThumbWidth { get; set; }
public string MediaThumbHeight { get; set; }
public string MediaAuthor { get; set; }
public ItemInfo() { }
public ItemInfo(string title, string link, string desc, string pubDate, string author, string guid) { /* ... */ }
public ItemInfo(string title, string link, string desc, string pubDate, string author, string guid,
string mediaUrl, string mediaTitle, string mediaDesc, string thumbUrl, string thumbW, string thumbH, string mediaAuthor) { /* ... */ }
}
// 產生 RSS
public void WriteRSS()
{
WritePrologue();
foreach (var item in _items)
{
WriteItem(item);
if (_hasMedia) WriteItemMedia(item);
WriteItemEnd();
}
WriteEnd();
_writer.Flush();
}
// 私有寫入方法 (節選)
private void WritePrologue()
{
_writer.WriteStartDocument();
_writer.WriteStartElement("rss");
_writer.WriteAttributeString("version", "2.0");
_writer.WriteAttributeString("xmlns:media", XMLNS_MEDIA);
_writer.WriteAttributeString("xmlns:dc", XMLNS_DC);
_writer.WriteStartElement("channel");
_writer.WriteElementString("title", TITLE);
_writer.WriteElementString("link", LINK);
_writer.WriteElementString("description", DESCRIPTION);
_writer.WriteElementString("language", LANGUAGE);
_writer.WriteElementString("pubDate", DateTime.Now.ToString("R"));
_writer.WriteElementString("lastBuildDate", DateTime.Now.ToString("R"));
_writer.WriteElementString("generator", GENERATOR);
_writer.WriteElementString("copyright", COPYRIGHT);
// Image 區塊
_writer.WriteStartElement("image");
_writer.WriteElementString("url", IMAGE_URL);
_writer.WriteElementString("title", IMAGE_TITLE);
_writer.WriteElementString("link", IMAGE_LINK);
_writer.WriteEndElement();
}
private void WriteItem(ItemInfo item)
{
_writer.WriteStartElement("item");
_writer.WriteElementString("title", item.ItemTitle);
_writer.WriteElementString("link", item.ItemLink);
_writer.WriteStartElement("description");
_writer.WriteCData(item.ItemDescription); // CDATA 避免 HTML 實體編碼
_writer.WriteEndElement();
_writer.WriteElementString("pubDate", item.ItemPubDate);
_writer.WriteElementString("dc:date", item.ItemPubDate);
_writer.WriteElementString("author", item.ItemAuthor);
_writer.WriteStartElement("guid");
_writer.WriteAttributeString("isPermaLink", "false");
_writer.WriteString(item.ItemGuid);
_writer.WriteEndElement();
}
private void WriteItemMedia(ItemInfo item)
{
if (string.IsNullOrEmpty(item.MediaContentUrl)) return;
_writer.WriteStartElement("media", "content", XMLNS_MEDIA);
_writer.WriteAttributeString("url", item.MediaContentUrl);
_writer.WriteAttributeString("type", "image/jpeg"); // 或 video/mp4 等
_writer.WriteEndElement();
_writer.WriteElementString("media", "title", XMLNS_MEDIA, item.MediaTitle);
_writer.WriteStartElement("media", "description", XMLNS_MEDIA);
_writer.WriteAttributeString("type", "html");
_writer.WriteString(item.MediaDescription);
_writer.WriteEndElement();
_writer.WriteStartElement("media", "thumbnail", XMLNS_MEDIA);
_writer.WriteAttributeString("url", item.MediaThumbUrl);
_writer.WriteAttributeString("width", item.MediaThumbWidth);
_writer.WriteAttributeString("height", item.MediaThumbHeight);
_writer.WriteEndElement();
_writer.WriteStartElement("media", "credit", XMLNS_MEDIA);
_writer.WriteAttributeString("role", "photographer");
_writer.WriteString(item.MediaAuthor);
_writer.WriteEndElement();
}
private void WriteItemEnd() => _writer.WriteEndElement(); //
private void WriteEnd()
{
_writer.WriteEndElement(); //
_writer.WriteEndElement(); //
_writer.WriteEndDocument();
}
}
public class RssHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/rss+xml";
context.Response.ContentEncoding = Encoding.UTF8;
using (XmlTextWriter writer = new XmlTextWriter(context.Response.OutputStream, Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
var items = new List
{
new RssBase.ItemInfo("文章標題 1", "https://example.com/post/1", "摘要...
", DateTime.Now.ToString("R"), "作者", "guid-1",
"https://example.com/img1.jpg", "圖片標題", "圖片描述", "https://example.com/thumb1.jpg", "120", "90", "攝影師"),
new RssBase.ItemInfo("文章標題 2", "https://example.com/post/2", "摘要...
", DateTime.Now.AddDays(-1).ToString("R"), "作者", "guid-2")
};
var rss = new RssBase(writer, hasMedia: true, items: items);
rss.WriteRSS();
}
}
public bool IsReusable => false;
}
// 在 Ashx 或 Controller 中
var items = db.Posts.Where(p => p.Published)
.OrderByDescending(p => p.PubDate)
.Take(20)
.Select(p => new RssBase.ItemInfo
{
ItemTitle = p.Title,
ItemLink = Url.Action("Detail", "Post", new { id = p.Id }, Request.Url.Scheme),
ItemDescription = p.Summary,
ItemPubDate = p.PubDate.ToString("R"),
ItemAuthor = p.Author.Name,
ItemGuid = p.Id.ToString(),
MediaContentUrl = p.CoverImageUrl,
MediaThumbUrl = p.ThumbnailUrl,
MediaThumbWidth = "300",
MediaThumbHeight = "200",
MediaAuthor = p.Photographer
}).ToList();
var rss = new RssBase(writer, true, items);
rss.WriteRSS();
var feed = new SyndicationFeed("標題", "描述", new Uri("https://example.com/"), "feed-id", DateTimeOffset.Now);
feed.Items = posts.Select(p => new SyndicationItem(p.Title, p.Summary, new Uri(p.Url), p.Id, p.PubDate)
{
Authors = { new SyndicationPerson(p.Author.Email, p.Author.Name, "") },
PublishDate = p.PubDate
}).ToList();
var formatter = new Rss20FeedFormatter(feed);
using (XmlWriter writer = XmlWriter.Create(context.Response.OutputStream, new XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true }))
formatter.WriteTo(writer);
.NET Framework 3.5+ 內建,支援 Atom 1.0、RSS 2.0,物件模型更豐富,建議新專案優先使用。