Blazor with an RSS Feed

30/05/2022
RSSBlazorC#

If you run a blog like this or any other website and you would like to expose a RSS Feed (like this very website) in your Blazor or any ASP.NET Core application you can do this with ease. We will use the help of a package named System.ServiceModel.Syndication.

And Blazor Webassembly?

The guide will only work on hosted versions of ASP.NET Core as Blazor Server is. If you host your Blazor WASM application on a GitHub page then this will not work. If you deliver your Blazor WASM via ASP.NET Core then go for it (in Visual Studio it is called ASP.NET Core hosted). The reason is that we need an active ASP.NET Core Server running for a controller which we have to create.

The Controller

The first thought might be that we render some kind of RSS feed inside a razor view, but that will not work for two reasons:

  1. We can't set a content type for a Blazor component / page.
  2. Even if we could it will be tricky to remove all the other stuff and have the XML structure of a normal RSS feed.

To do this we do the "old" ASP.NET Core way of doing things. We just add support for controllers in our Blazor App. For that go either to your Startup.cs or Program.cs and extend WebApplication with the following:

app.UseRouting();

app.MapControllers(); // Add the controller support here

app.MapBlazorHub();

Now that was easy, wasn't it? And the best thing is that we are halfway done.

Nuget package to the rescue

I don't want to deal with how a RSS feed is exactly formed. Which means I don't want to create the xml file on my own. And we don't have to, because there is a nice package called System.ServiceModel.Syndication. This does all the magic for us. So let's include this to our project.

Create the controller

Let's create a new class called RssFeedController which has the following content:

using Microsoft.AspNetCore.Mvc;

namespace BlazorRSSFeed.Controller;

public class RssFeedController : ControllerBase
{
    [ResponseCache(Duration = 1200)]
    [HttpGet]
    [Route("feed.rss")]
    public async Task<IActionResult> GetRssFeed()
    {
        return Accepted();
    }
}

Now the ResponseCache of course is optional. I just wanted to highlight that you can take the "normal" ASP.NET Core stuff as in any other Web API project. RSS Feeds are normal GET request and we defined the route via: [Route("feed.rss")]. Now if we hit compile and go to our browser and go to our endpoint like that: https://localhost:7207/feed.rss we see an empty page. That is good because it is working as expected.

Now let's fill the content:

public async Task<IActionResult> GetRssFeed()
{
    // Get the current url
    var url = $"{Request.Scheme}://{Request.Host}{Request.PathBase}";
    
    // This object reflects our RSS feed root item
    var feed = new SyndicationFeed(
        "Title",
        "This is a sample title",
        new Uri(url))
    {
        // You could create a list here of your blog posts for example
        Items = new[]
        {
            new SyndicationItem(
                "A Blog Post",
                "Somecontent",
                new Uri(url + "/url-to-your-sub-item"))
        }
    };

    // Create the XML Writer with it's settings
    var settings = new XmlWriterSettings
    {
        Encoding = Encoding.UTF8,
        NewLineHandling = NewLineHandling.Entitize,
        NewLineOnAttributes = true,
        Indent = true, // Makes it easier to read for humans
        Async = true, // You can omit this if you don't use the async API
    };

    using var stream = new MemoryStream();
    await using var xmlWriter = XmlWriter.Create(stream, settings);
    // Create the RSS Feed
    var rssFormatter = new Rss20FeedFormatter(feed, false);
    rssFormatter.WriteTo(xmlWriter);
    await xmlWriter.FlushAsync();

    return File(stream.ToArray(), "application/rss+xml; charset=utf-8");
}

The result

If we know go again to our RSS feed in the browser, we will see the follwing:

<?xml version="1.0" encoding="utf-8"?>
<rss
  version="2.0">
  <channel>
    <title>Title</title>
    <link>https://localhost:7207/</link>
    <description>This is a sample title</description>
    <item>
      <link>https://localhost:7207/url-to-your-sub-item</link>
      <title>A Blog Post</title>
      <description>Somecontent</description>
    </item>
  </channel>
</rss>

Resources

  • The code for this blog post can be found here
  • The majority of code samples can be found here
  • The implementation for this very blog can be found here
0
An error has occurred. This application may no longer respond until reloaded. Reload x