feat: implement rss feed
This commit is contained in:
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
"cSpell.words": [
|
||||
"Antiforgery",
|
||||
"blazor",
|
||||
"Entitize",
|
||||
"Hsts",
|
||||
"Markdig",
|
||||
"msedge"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.36.2" />
|
||||
<PackageReference Include="System.ServiceModel.Syndication" Version="8.0.0" />
|
||||
<PackageReference Include="TestableIO.System.IO.Abstractions.Wrappers" Version="21.0.2" />
|
||||
<PackageReference Include="WebStoating.Markdig.Prism" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
+68
-1
@@ -1,3 +1,8 @@
|
||||
using System.ServiceModel.Syndication;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.ConfigureOptions<FilePostServiceOptionsSetup>();
|
||||
@@ -21,11 +26,73 @@ app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.UseStatusCodePagesWithRedirects("/Error/{0}");
|
||||
|
||||
app
|
||||
.MapGet("/rss", async (HttpContext context, IPostService postService) =>
|
||||
{
|
||||
var req = context.Request;
|
||||
var url = $"{req.Scheme}://{req.Host}{req.PathBase}";
|
||||
|
||||
var posts = await postService.GetPostsAsync();
|
||||
|
||||
var items = posts.Select(post =>
|
||||
{
|
||||
var uri = new Uri($"{url}/{post.Slug}");
|
||||
|
||||
var item = new SyndicationItem(
|
||||
post.Title,
|
||||
post.Lead,
|
||||
uri,
|
||||
post.Slug,
|
||||
post.PublishedAt
|
||||
);
|
||||
|
||||
return item;
|
||||
});
|
||||
|
||||
var feed = new SyndicationFeed(
|
||||
"journal",
|
||||
"A blog by Stevan Freeborn",
|
||||
new Uri(url)
|
||||
)
|
||||
{
|
||||
Items = items,
|
||||
};
|
||||
|
||||
XNamespace atom = "http://www.w3.org/2005/Atom";
|
||||
feed.ElementExtensions.Add(
|
||||
new XElement(atom + "link",
|
||||
new XAttribute("href", url + "/rss"),
|
||||
new XAttribute("rel", "self"),
|
||||
new XAttribute("type", "application/rss+xml")
|
||||
)
|
||||
);
|
||||
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
NewLineHandling = NewLineHandling.Entitize,
|
||||
Indent = true,
|
||||
Async = true,
|
||||
};
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
using var writer = XmlWriter.Create(stream, settings);
|
||||
|
||||
var rssFormatter = new Rss20FeedFormatter(feed, false);
|
||||
rssFormatter.WriteTo(writer);
|
||||
await writer.FlushAsync();
|
||||
|
||||
return Results.File(stream.ToArray(), "application/xml");
|
||||
})
|
||||
.WithDisplayName("RSS Feed")
|
||||
.WithDescription("RSS feed for the blog");
|
||||
|
||||
app
|
||||
.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
|
||||
app.UseStatusCodePagesWithRedirects("/Error/{0}");
|
||||
|
||||
app.Run();
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.ServiceModel.Syndication;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Blog.Tests.EndToEnd;
|
||||
|
||||
[TestFixture]
|
||||
public class RssTests : BlogTest
|
||||
{
|
||||
[Test]
|
||||
public async Task Task_Rss_WhenFetched_ItShouldReturnRssFeed()
|
||||
{
|
||||
var response = await Page.APIRequest.GetAsync("/rss");
|
||||
response.Status.Should().Be((int)HttpStatusCode.OK);
|
||||
|
||||
var xml = await response.BodyAsync();
|
||||
|
||||
var streamReader = new StreamReader(
|
||||
new MemoryStream(xml),
|
||||
Encoding.UTF8
|
||||
);
|
||||
|
||||
|
||||
var settings = new XmlReaderSettings
|
||||
{
|
||||
Async = true
|
||||
};
|
||||
|
||||
using var xmlReader = XmlReader.Create(streamReader, settings);
|
||||
var feed = SyndicationFeed.Load(xmlReader);
|
||||
|
||||
feed.Title.Text.Should().Be("journal");
|
||||
feed.Description.Text.Should().Be("A blog by Stevan Freeborn");
|
||||
feed.Items.Should().HaveCount(2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user