Overview
In this post, we will see how to read RSS feeds from the C# Corner website and display the feeds in a Blazor project. We will see how to get all post feeds for an author (author ID can be given by the user), feeds for the latest posts, feeds for featured articles, and feeds for top-read posts.
RSS (originally RDF Site Summary; later, two approaches emerged, which used the acronyms “Rich Site Summary” and “Really Simple Syndication” respectively). It is a type of web feed that allows users and applications to access updates to the online content of a website in a standardized, computer-readable format.
Blazor is an experimental .NET web framework using C#/Razor and HTML that runs in the browser with WebAssembly. Blazor provides all the benefits of a client-side web UI framework using .NET on the client and optionally, on the server.
I have already written many articles on Blazor in C# Corner. If you are new to Blazor, please refer to the below articles to get started with Blazor.
Create a Blazor project in Visual Studio
Create a new Blazor project in Visual Studio. I am using the free community edition of Visual Studio 2017.
Choose .NET Core -> ASP.NET Core Web Application template.
Currently, Blazor supports three different templates. We will choose the “Blazor (ASP.NET Core hosted)” template for our project.
Our solution will be ready in a few moments. Please note that there are three projects created in our solution - “Client”, “Server”, and “Shared”.
By default, Blazor created many files in these three projects. We can remove all the unwanted files like “Counter. cshtml”, “FetchData.cshtml”, “SurveyPrompt.cshtml” from the Client project and “SampleDataController.cs” file from the Server project and remove the “WeatherForecast.cs” file from the shared project too.
Create a new “Models” folder in the “Shared” project and add a “Feed” class file inside this folder. We will add two classes “AuthorPosts” and “Feed” in this file.
Feed. cs
using System;
using System.Collections.Generic;
namespace CsharpCornerRSSBlazor.Shared.Models
{
public class AuthorPosts
{
public string AuthorName { get; set; }
public IEnumerable<Feed> Feeds { get; set; }
}
public class Feed
{
public string Link { get; set; }
public string Title { get; set; }
public string FeedType { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime PubDate { get; set; }
public string PublishDate { get; set; }
public Feed()
{
Link = "";
Title = "";
FeedType = "";
Author = "";
Content = "";
PubDate = DateTime.Today;
PublishDate = DateTime.Today.ToString("dd-MMM-yyyy");
}
}
}
In the “Feed” class, we have defined all the properties for RSS feeds such as “Link”, “Title”, “FeedType”, “Author”, “Content”, “PubDate” and “PublishDate”.
“PublishDate” is a string property that is also used for keeping post-published data but will be converted to a string format dd-MMM-yyyy. Mainly I added this additional property to avoid the confusion over different date formats used in various countries.
In the “AuthorPost” class, we keep “AuthorName” and an array of feeds for a given author.
Create an API controller in the “Server” project
We can add code for getting all posts for a given author.
Code for "All Posts" for a given author.
readonly CultureInfo culture = new CultureInfo("en-US");
[Route("allposts/{authorId}")]
[HttpGet]
public AuthorPosts AllPosts(string authorId)
{
AuthorPosts authorPosts = new AuthorPosts();
try
{
XDocument doc = XDocument.Load("https://www.c-sharpcorner.com/members/" + authorId + "/rss");
var entries = from item in doc.Root.Descendants().First(i => i.Name.LocalName == "channel").Elements().Where(i =>
i.Name.LocalName == "item")
select new Feed
{
Content = item.Elements().First(i => i.Name.LocalName == "description").Value,
Link = (item.Elements().First(i => i.Name.LocalName == "link").Value).StartsWith("/") ? "https://www.c-sharpcorner.com" + item.Elements().First(i => i.Name.LocalName == "link").Value : item.Elements().First(i => i.Name.LocalName == "link").Value,
PubDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture),
PublishDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture).ToString("dd-MMM-yyyy"),
Title = item.Elements().First(i => i.Name.LocalName == "title").Value,
FeedType = (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("blog") ? "Blog" : (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("news") ? "News" : "Article",
Author = item.Elements().First(i => i.Name.LocalName == "author").Value
};
authorPosts.AuthorName = entries.FirstOrDefault()?.Author;
authorPosts.Feeds = entries.OrderByDescending(o => o.PubDate);
return authorPosts;
}
catch
{
authorPosts.AuthorName = "NOT FOUND!";
List<Feed> feeds = new List<Feed>();
Feed feed = new Feed();
feeds.Add(feed);
authorPosts.Feeds = feeds;
return authorPosts;
}
}
We have passed the author ID as a parameter. Currently, C# Corner returns “links” for “Blogs” without a full URL. So, I added a ternary operator to add the full URL for blog posts. I have also checked the “link” value to differentiate post types as “Articles”, “Blogs” and “News”
Code for Latest Posts
[Route("latestposts")]
[HttpGet]
public IEnumerable<Feed> LatestPosts()
{
try
{
XDocument doc = XDocument.Load("https://www.c-sharpcorner.com/rss/latestcontentall.aspx");
var entries = from item in doc.Root.Descendants().First(i => i.Name.LocalName == "channel").Elements().Where(i => i.Name.LocalName == "item")
select new Feed
{
Content = item.Elements().First(i => i.Name.LocalName == "description").Value,
Link = (item.Elements().First(i => i.Name.LocalName == "link").Value).StartsWith("/") ? "https://www.c-sharpcorner.com" + item.Elements().First(i => i.Name.LocalName == "link").Value : item.Elements().First(i => i.Name.LocalName == "link").Value,
PubDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture),
PublishDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture).ToString("dd-MMM-yyyy"),
Title = item.Elements().First(i => i.Name.LocalName == "title").Value,
FeedType = (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("blog") ? "Blog" : (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("news") ? "News" : "Article",
Author = item.Elements().First(i => i.Name.LocalName == "author").Value
};
return entries.OrderByDescending(o => o.PubDate);
}
catch
{
List<Feed> feeds = new List<Feed>();
Feed feed = new Feed();
feeds.Add(feed);
return feeds;
}
}
The only difference in this method from the previous method is, that we gave the RSS feed URL statically.
Code for Featured Posts
[Route("featuredposts")]
[HttpGet]
public IEnumerable<Feed> FeaturedPosts()
{
try
{
XDocument doc = XDocument.Load("https://www.c-sharpcorner.com/rss/featuredarticles.aspx");
var entries = from item in doc.Root.Descendants().First(i => i.Name.LocalName == "channel").Elements().Where(i => i.Name.LocalName == "item")
select new Feed
{
Content = item.Elements().First(i => i.Name.LocalName == "description").Value,
Link = (item.Elements().First(i => i.Name.LocalName == "link").Value).StartsWith("/") ? "https://www.c-sharpcorner.com" + item.Elements().First(i => i.Name.LocalName == "link").Value : item.Elements().First(i => i.Name.LocalName == "link").Value,
PubDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture),
PublishDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture).ToString("dd-MMM-yyyy"),
Title = item.Elements().First(i => i.Name.LocalName == "title").Value,
FeedType = (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("blog") ? "Blog" : (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("news") ? "News" : "Article",
Author = item.Elements().First(i => i.Name.LocalName == "author").Value
};
return entries.OrderByDescending(o => o.PubDate);
}
catch
{
List<Feed> feeds = new List<Feed>();
Feed feed = new Feed();
feeds.Add(feed);
return feeds;
}
}
This is the same as the previous method, the only difference is the RSS feed URL.
Code for Top Read Posts
[Route("topposts")]
[HttpGet]
public IEnumerable<Feed> TrendingPosts()
{
try
{
XDocument doc = XDocument.Load("https://www.c-sharpcorner.com/rss/toparticles.aspx");
var entries = from item in doc.Root.Descendants().First(i => i.Name.LocalName == "channel").Elements().Where(i => i.Name.LocalName == "item")
select new Feed
{
Content = item.Elements().First(i => i.Name.LocalName == "description").Value,
Link = (item.Elements().First(i => i.Name.LocalName == "link").Value).StartsWith("/") ? "https://www.c-sharpcorner.com" + item.Elements().First(i => i.Name.LocalName == "link").Value : item.Elements().First(i => i.Name.LocalName == "link").Value,
PubDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture),
PublishDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture).ToString("dd-MMM-yyyy"),
Title = item.Elements().First(i => i.Name.LocalName == "title").Value,
FeedType = (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("blog") ? "Blog" : (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("news") ? "News" : "Article",
Author = item.Elements().First(i => i.Name.LocalName == "author").Value
};
return entries;
}
catch
{
List<Feed> feeds = new List<Feed>();
Feed feed = new Feed();
feeds.Add(feed);
return feeds;
}
}
This is also the same as the previous method, the only difference is the RSS feed URL.
We have added all the source code for the Controller class. Now, we can go to the “Client” project and modify the “NavMenu.cshtml” Razor view inside the “Shared” folder. This Razor view will be used for navigating the menu items.
NavMenu.cshtml
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">C# Corner RSS Blazor App</a>
<button class="navbar-toggler" onclick=@ToggleNavMenu>
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class=@(collapseNavMenu ? "collapse" : null) onclick=@ToggleNavMenu>
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match=NavLinkMatch.All>
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="/allposts">
<span class="oi oi-list-rich" aria-hidden="true"></span> All Posts by an Author
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="/latestposts">
<span class="oi oi-list-rich" aria-hidden="true"></span> Latest Posts
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="/featuredposts">
<span class="oi oi-list-rich" aria-hidden="true"></span> Featured Posts
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="/topposts">
<span class="oi oi-list-rich" aria-hidden="true"></span> Top Read Posts
</NavLink>
</li>
</ul>
</div>
@functions {
bool collapseNavMenu = true;
void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
We can add a new Razor view under the “Pages” folder to show the feeds for a given author.
AllPosts.cshtml
@using CsharpCornerRSSBlazor.Shared.Models
@page "/allposts"
@inject HttpClient Http
<h4>C# Corner All Post Details by an Author</h4>
<input placeholder="Enter Author Id" bind="@authorId" />
<input type="button" class="btn btn-default" onclick="@(async () => await GetAllPosts())" value="Get Posts" />
<br />
<br />
<p><b>@author</b></p>
@if (feeds == null)
{
if (!pageLoaded && authorId != "" && author != "Invalid Author Id!")
{
<p><em>Loading...</em></p>
}
}
else
{
if (!author.ToUpperInvariant().Contains("NOT FOUND"))
{
counter = 0;
<table class='table'>
<thead>
<tr>
<th>Sl.No.</th>
<th>Post Title (With Link)</th>
<th>Post Type</th>
<th>Content</th>
<th>Publish Date</th>
</tr>
</thead>
<tbody>
@foreach (var feed in feeds)
{
counter++;
<tr>
<td>@counter</td>
<td><NavLink [email protected] target="_blank">@feed.Title</NavLink></td>
<td>@feed.FeedType</td>
<td>@feed.Content</td>
<td>@feed.PublishDate</td>
</tr>
}
</tbody>
</table>
}
}
@functions {
Feed[] feeds;
AuthorPosts authorPosts;
string authorId;
bool pageLoaded;
int counter;
string author;
protected override void OnInit()
{
authorId = "";
pageLoaded = true;
author = "";
}
protected async Task GetAllPosts()
{
author = "";
pageLoaded = false;
feeds = null;
if (authorId != "")
{
authorPosts = await Http.GetJsonAsync<AuthorPosts>("/api/feeds/allposts/" + authorId);
if (authorPosts != null)
{
if (authorPosts.AuthorName.ToUpperInvariant().Contains("NOT FOUND"))
{
author = "Invalid Author Id!";
}
else
{
author = "Author Name : " + authorPosts.AuthorName;
feeds = authorPosts.Feeds.ToArray();
}
}
}
else
{
author = "Author Id should not be blank";
}
}
}
I have created an input text field to get the author ID and after hitting the “Get Posts” button, the “GetAllPosts” method will be triggered and if the given author ID has any data available, it will be displayed in the HTML table. Otherwise, an “Invalid Author ID” notification will be displayed on the screen.
We can create another Razor view for getting the latest post details.
LatestPosts.cshtml
@using CsharpCornerRSSBlazor.Shared.Models
@page "/latestposts"
@inject HttpClient Http
<h4>C# Corner Latest Posts</h4>
@if (feeds == null)
{
<p><em>Loading...</em></p>
}
else
{
counter = 0;
<table class='table'>
<thead>
<tr>
<th>Sl.No.</th>
<th>Post Title (With Link)</th>
<th>Post Type</th>
<th>Content</th>
<th>Publish Date</th>
<th>Author</th>
</tr>
</thead>
<tbody>
@foreach (var feed in feeds)
{
counter++;
<tr>
<td>@counter</td>
<td><NavLink [email protected] target="_blank">@feed.Title</NavLink></td>
<td>@feed.FeedType</td>
<td>@feed.Content</td>
<td>@feed.PublishDate</td>
<td>@feed.Author</td>
</tr>
}
</tbody>
</table>
}
@functions {
Feed[] feeds;
int counter;
protected override async Task OnInitAsync()
{
feeds = null;
feeds = await Http.GetJsonAsync<Feed[]>("/api/feeds/latestposts");
}
}
In this file, we have displayed all the latest article details. Please note that currently C# corner returns only 100 top posts in RSS feeds.
We can create another Razor view for getting featured post details.
FeaturedPosts.cshtml
@using CsharpCornerRSSBlazor.Shared.Models
@page "/featuredposts"
@inject HttpClient Http
<h4>C# Corner Featured Post Details</h4>
@if (feeds == null)
{
<p><em>Loading...</em></p>
}
else
{
counter = 0;
<table class='table'>
<thead>
<tr>
<th>Sl.No.</th>
<th>Post Title (With Link)</th>
<th>Post Type</th>
<th>Content</th>
<th>Publish Date</th>
<th>Author</th>
</tr>
</thead>
<tbody>
@foreach (var feed in feeds)
{
counter++;
<tr>
<td>@counter</td>
<td><NavLink [email protected] target="_blank">@feed.Title</NavLink></td>
<td>@feed.FeedType</td>
<td>@feed.Content</td>
<td>@feed.PublishDate</td>
<td>@feed.Author</td>
</tr>
}
</tbody>
</table>
}
@functions {
Feed[] feeds;
int counter;
protected override async Task OnInitAsync()
{
feeds = null;
feeds = await Http.GetJsonAsync<Feed[]>("/api/feeds/featuredposts");
}
}
We can add one more Razor View for getting the top-read post details.
TopPosts.cshtml
@using CsharpCornerRSSBlazor.Shared.Models
@page "/topposts"
@inject HttpClient Http
<h4>C# Corner Top Read Posts</h4>
@if (feeds == null)
{
<p><em>Loading...</em></p>
}
else
{
counter = 0;
<table class='table'>
<thead>
<tr>
<th>Sl.No.</th>
<th>Post Title (With Link)</th>
<th>Post Type</th>
<th>Content</th>
<th>Publish Date</th>
<th>Author</th>
</tr>
</thead>
<tbody>
@foreach (var feed in feeds)
{
counter++;
<tr>
<td>@counter</td>
<td><NavLink [email protected] target="_blank">@feed.Title</NavLink></td>
<td>@feed.FeedType</td>
<td>@feed.Content</td>
<td>@feed.PublishDate</td>
<td>@feed.Author</td>
</tr>
}
</tbody>
</table>
}
@functions {
Feed[] feeds;
int counter;
protected override async Task OnInitAsync()
{
feeds = null;
feeds = await Http.GetJsonAsync<Feed[]>("/api/feeds/topposts");
}
}
We can modify the “Index.cshtml” Razor View also.
Index. cshtml
@page "/"
<h3>Get C# Corner RSS Feeds in Blazor Project</h3>
<hr />
<p>
We can see how to read RSS feeds from C# Corner site and display the feeds in a Blazor project.
We will see how to get all posts feeds for an author (author id can be given by user),
feeds for latest posts, feeds for featured articles, and feeds for top read posts.
</p>
We have completed all the coding parts. We can now run the application. The home page will look like the below image.
We can click the “All Posts by an Author” link.
It will ask the user to enter an author ID and click the “Get Posts” button.
I have given my own author ID. Now we have got all my post details.
Please note, the post title will be mapped with the post link. So, if we click the title, we can open the post in a new tab.
If you give an invalid author ID, it will display the below message.
We can click the “Latest Posts” link in the navigation menu to get all the latest post details.
I have taken these details on November 18. It will display all the posts in date-wise descending order.
We can click the “Featured Posts” link to get all the featured article details.
We can get the top-read post details by clicking the “Top Read Posts” link in the navigation menu.
Please note, that this is not in date-wise order. Instead, it's listed in the order of the user-read count. (Top read count posts come first.)
Deploy the Blazor application on Azure
If you want to check this simple application, I have hosted the Blazor app on Azure as a Web App. Please click this URL to run the application.
Conclusion
In this post, we have seen how to get RSS feeds from the C# Corner site and display this data in a Blazor project. We have got all the post details for a given author. We have also seen how to get RSS feeds for the latest posts, featured posts, and top-read posts.
We will discuss more features of the Blazor framework in upcoming posts.