Built-in BlogSite routes
UseBlogSite mounts the Razor pages that serve the homepage, archive, tag index, per-tag listing, and individual posts, plus an optional /rss.xml endpoint. Pages are discovered via RazorPageContentService; AddBlogSite registers Pennington.BlogSite as an additional routing assembly so Razor picks them up.
Entry point
UseBlogSite calls MapRazorComponents<App>, which discovers every @page-annotated component in Pennington.BlogSite.dll; when BlogSiteOptions.EnableRss is true it additionally maps a MapGet("/rss.xml", …) endpoint that delegates to BlogSiteContentService.GetRssXmlAsync. The /sitemap.xml endpoint is mounted by UsePennington via SitemapService, not by UseBlogSite.
Routes
All routes registered by UseBlogSite, ordered by the surface they serve.
| Path | Method | Option controlling it | Description |
|---|---|---|---|
/ |
GET |
— (fixed) | Homepage Razor page (Home.razor); renders BlogSiteOptions.HeroContent, the ten most recent posts via BlogSummary, and the sidebar modules fed by MyWork/Socials/AuthorBio. |
/archive |
GET |
— (fixed) | Full archive Razor page (Archive.razor); renders BlogContentResolver.GetAllPostsAsync() in reverse chronological order through BlogSummary. |
/tags |
GET |
TagsPageUrl (see note) |
Tag index Razor page (Tags.razor); lists every BlogTag with post counts from BlogContentResolver.GetTagsWithCountsAsync(). |
/topics |
GET |
— (fixed alias) | Second @page directive on Tags.razor exposing the same component under /topics as a built-in alias. |
/tags/{TagEncodedName} |
GET |
TagsPageUrl (see note) |
Per-tag listing Razor page (Tag.razor); resolves the encoded tag name via BlogContentResolver.GetPostsByTagAsync and renders matching posts through BlogPostsList. |
/topics/{TagEncodedName} |
GET |
— (fixed alias) | Second @page directive on Tag.razor exposing the per-tag listing under /topics/{TagEncodedName} as a built-in alias. |
/blog/{*fileName} |
GET |
BlogBaseUrl (see note) |
Post-rendering catch-all Razor page (Blog.razor); looks up the post by {BlogBaseUrl}/{fileName} via BlogContentResolver.GetPostByUrlAsync and renders it through BlogPost with OpenGraph and structured-data head tags. |
/rss.xml |
GET |
EnableRss |
MapGet endpoint in UseBlogSite that delegates to BlogSiteContentService.GetRssXmlAsync; omitted entirely when EnableRss is false. |
Note on
TagsPageUrlandBlogBaseUrl. The@pagedirectives onTags.razor,Tag.razor, andBlog.razorare string literals ("/tags","/topics","/blog/{*fileName}") and are not templated fromBlogSiteOptions.TagsPageUrl(default"/tags") andBlogBaseUrl(default"/blog") are used byBlogContentResolver/BlogSiteContentServiceto build tag and post URLs that match these page routes; changing them away from the defaults requires supplying replacement Razor pages viaAdditionalRoutingAssemblies. SeeBlogSiteOptions.
Option-to-route matrix
BlogSiteOptions knobs that affect route registration or URL resolution, one row per option.
| Option | Default | Routes it affects | Effect |
|---|---|---|---|
BlogBaseUrl |
"/blog" |
/blog/{*fileName} |
Consumed by BlogContentResolver.GetPostByUrlAsync as the URL prefix; the @page "/blog/{*fileName}" directive on Blog.razor is a fixed string, so this value must match the literal route for posts to resolve. |
EnableRss |
true |
/rss.xml |
Gates the MapGet("/rss.xml", …) call in UseBlogSite; when false the endpoint is not registered and the static crawler does not emit rss.xml. |
EnableSitemap |
true |
/sitemap.xml (from UsePennington) |
Controls inclusion of BlogSite routes in the sitemap emitted by SitemapService; the sitemap endpoint itself is mounted by UsePennington, not UseBlogSite. |
TagsPageUrl |
"/tags" |
/tags, /tags/{TagEncodedName} |
Consumed by BlogContentResolver when composing per-tag URLs; the @page directives on Tags.razor and Tag.razor are fixed string literals, so tag URLs and page routes only align at the default "/tags" value (the /topics aliases are always present). |
Example
A BlogSite host that mounts every route on this page via a single UseBlogSite call.
using Pennington.BlogSite;
var builder = WebApplication.CreateBuilder(args);
// Swap the bare `AddPennington` host for the BlogSite template. `AddBlogSite`
// wires the full blog experience on top of Pennington core — a Blazor
// layout with a home page that lists recent posts, an /archive page,
// /blog/<slug> post pages, /tags and /tags/<name> listings, and an
// /rss.xml feed — all driven from `BlogSiteOptions`.
builder.Services.AddBlogSite(() => new BlogSiteOptions
{
SiteTitle = "Scaffold Blog",
Description = "A minimal BlogSite scaffold showing AddBlogSite, UseBlogSite, and RunBlogSiteAsync.",
CanonicalBaseUrl = "https://example.com",
// BlogSite defaults put posts under `{ContentRootPath}/{BlogContentPath}`
// (Content/Blog) and serves them at `BlogBaseUrl` (/blog). Tag listings
// live at `TagsPageUrl` (/tags). Overriding the defaults is as simple as
// setting the matching property — shown here with the defaults for
// clarity.
ContentRootPath = "Content",
BlogContentPath = "Blog",
BlogBaseUrl = "/blog",
TagsPageUrl = "/tags",
// Author identity feeds into the RSS channel, JSON-LD article markup,
// and any post that omits its own `author:` front-matter value.
AuthorName = "Author Name",
AuthorBio = "Writing about software, tools, and the occasional side project.",
});
var app = builder.Build();
// `UseBlogSite` mounts antiforgery, static files, Razor component routing
// (Home/Archive/Blog/Tag/Tags live inside Pennington.BlogSite.dll), the
// MonorailCSS response processor, and the core Pennington middleware —
// all in the right order. When `EnableRss` is true (the default) it also
// maps `/rss.xml` so the static crawler picks the feed up.
app.UseBlogSite();
// `RunBlogSiteAsync` delegates to `RunOrBuildAsync`, so `dotnet run` serves the
// blog live and `dotnet run -- build <baseUrl> <outputDir>` generates static
// HTML. Both positional args are optional (defaults: `/` and `output`).
await app.RunBlogSiteAsync(args);
The example boots Pennington.BlogSite with scaffold options; all eight routes listed above — including /rss.xml, because EnableRss defaults to true — are live in dev and in the static build.
See also
- Reference:
BlogSiteOptions - Reference: Built-in
SocialIconsRenderFragments - How-to: Customize DocSite layouts and components
- How-to: Configure the BlogSite homepage