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:
- We can't set a content type for a Blazor component / page.
- 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>