|
| 1 | +namespace BlazorBlog.Feeds |
| 2 | +{ |
| 3 | + using System.Globalization; |
| 4 | + using System.Xml.Linq; |
| 5 | + using BlazorBlog.Application.Models; |
| 6 | + |
| 7 | + public static class RssFeedDocument |
| 8 | + { |
| 9 | + private static readonly XNamespace ContentNamespace = "http://purl.org/rss/1.0/modules/content/"; |
| 10 | + |
| 11 | + public static string Create( |
| 12 | + IEnumerable<BlogPostVm> posts, |
| 13 | + Uri baseUri, |
| 14 | + Uri feedUri, |
| 15 | + FeedOptions options, |
| 16 | + Func<string, string> sanitizeSummary, |
| 17 | + Func<string, string> renderSafeContent) |
| 18 | + { |
| 19 | + var channel = new XElement( |
| 20 | + "channel", |
| 21 | + new XElement("title", options.Title), |
| 22 | + new XElement("link", baseUri.AbsoluteUri), |
| 23 | + new XElement("description", options.Description), |
| 24 | + new XElement("language", "en"), |
| 25 | + new XElement("lastBuildDate", FormatRssDate(DateTime.UtcNow))); |
| 26 | + |
| 27 | + foreach (var post in posts) |
| 28 | + { |
| 29 | + var postUri = new Uri(baseUri, $"posts/{Uri.EscapeDataString(post.Slug)}"); |
| 30 | + var publishedAt = (post.PublishedAt ?? DateTime.UtcNow).ToUniversalTime(); |
| 31 | + var safeSummary = sanitizeSummary(post.Introduction ?? string.Empty); |
| 32 | + var safeContent = renderSafeContent(post.Content ?? string.Empty); |
| 33 | + |
| 34 | + channel.Add( |
| 35 | + new XElement( |
| 36 | + "item", |
| 37 | + new XElement("title", post.Title), |
| 38 | + new XElement("link", postUri.AbsoluteUri), |
| 39 | + new XElement("guid", new XAttribute("isPermaLink", "true"), postUri.AbsoluteUri), |
| 40 | + new XElement("pubDate", FormatRssDate(publishedAt)), |
| 41 | + new XElement("description", new XCData(safeSummary)), |
| 42 | + new XElement(ContentNamespace + "encoded", new XCData(safeContent)))); |
| 43 | + } |
| 44 | + |
| 45 | + var document = new XDocument( |
| 46 | + new XDeclaration("1.0", "utf-8", null), |
| 47 | + new XElement( |
| 48 | + "rss", |
| 49 | + new XAttribute("version", "2.0"), |
| 50 | + new XAttribute(XNamespace.Xmlns + "content", ContentNamespace), |
| 51 | + new XAttribute(XNamespace.Xmlns + "atom", "http://www.w3.org/2005/Atom"), |
| 52 | + channel)); |
| 53 | + |
| 54 | + channel.AddFirst( |
| 55 | + new XElement( |
| 56 | + XName.Get("link", "http://www.w3.org/2005/Atom"), |
| 57 | + new XAttribute("href", feedUri.AbsoluteUri), |
| 58 | + new XAttribute("rel", "self"), |
| 59 | + new XAttribute("type", "application/rss+xml"))); |
| 60 | + |
| 61 | + return document.ToString(SaveOptions.DisableFormatting); |
| 62 | + } |
| 63 | + |
| 64 | + private static string FormatRssDate(DateTime value) |
| 65 | + => value.ToUniversalTime().ToString("R", CultureInfo.InvariantCulture); |
| 66 | + } |
| 67 | +} |
0 commit comments