Kiedy zainteresowałem się uczestnictwem w Daj Się Poznać 2017, okazało się, że jedynym wymogiem, którego nie spełnia mój blog jest kanał RSS. Od tego więc zaczniemy wpisy w ramach konkursu. Wbrew pozorom, temat wcale nie jest skomplikowany: jedna niewielka klasa + jedna akcja kontrolera + jeden istotny szczegół w widoku i voilà!

Co chcemy osiągnąć? Celem jest utworzenie pliku XML, bo w tym właśnie formacie operują kanały RSS. Zacznijmy od dodania prostej klasy dziedziczącej po ActionResult, którą ja nazwałem FeedResult. Oto ona:

 

using System.ServiceModel.Syndication;
using System.Web.Mvc;
using System.Xml;

namespace LDevelopment.ActionResults
{
    public class FeedResult : ActionResult
    {
        private SyndicationFeed Feed { get; }

        public FeedResult(SyndicationFeed feed)
        {
            Feed = feed;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            var response = context.HttpContext.Response;

            response.ContentType = "application/rss+xml";

            if (Feed != null)
            {
                var formatter = new Rss20FeedFormatter(Feed);

                using (var writer = new XmlTextWriter(response.Output))
                {
                    writer.Formatting = Formatting.Indented;

                    formatter.WriteTo(writer);
                }
            }
        }
    }
}

 

Następnie, w kontrolerze Blog dodajmy akcję Feed, która zbierze kilka ostatnich postów, z każdego tworząc obiekt klasy SyndicationItem. Gotową listę wrzucamy do klasy SyndicationFeed, uzupełniając jednocześnie o kilka istotnych propert jak nazwa, opis czy adres strony i wykorzystujemy wcześniej utworzoną klasę FeedResult by zwrócić elegancki plik XML

 

public ActionResult Feed()
{
    var items = new List<SyndicationItem>();

    Repository
        .All<PostModel>(x => x.IsReleased)
        .OrderByDescending(x => x.ReleaseDate)
        .ThenBy(x => x.Title)
        .Take(_pageSize)
        .ForEach(x => items.Add(
            new SyndicationItem(
                x.Title, 
                x.Text, 
                new Uri($"https://{Request.Url.Host}{Url.Action("Details")}?url={x.Url}"), 
                x.Url, 
                x.ReleaseDate)));

    var feed = new SyndicationFeed(
        Resources.Resources.SiteName, 
        Resources.Resources.SiteDescription, 
        new Uri($"https://{Request.Url.Host}"), 
        items);

    return new FeedResult(feed);
}

 

Przydałby się jeszcze link w nagłówku strony (widok _Layout.cshtml), który poinformuje przeglądarki i czytniki RSS o tym, że to właśnie pod tą akcją tego kontrolera mają szukać źródła newsów na naszym blogu

 

<link rel="alternate" type="application/rss+xml" href="@Url.Action("Feed", "Blog")" />

 

Sprawdziłem działanie kanału na feedly.com - czytniku on-line, z którego sam korzystam na co dzień i wygląda na to, że działa jak powinno. Możemy więc spokojnie zaczynać pisać posty w ramach Daj Się Poznać. Zaczynamy! :)