DI and middleware extension methods
The complete roster of public extension methods Pennington exposes for wiring the library into an ASP.NET Core host — Add* (DI registration), Use* (middleware and endpoints), and Run* (host entry points). Grouped below by receiver type; each method is declared in an *Extensions static class under its owning feature namespace.
IServiceCollection extensions
DI registration entry points. Each method's options surface is documented on its own reference page, linked from the method's xmldoc.
AddApiMetadataFromCompiledAssemblyIServiceCollection AddApiMetadataFromCompiledAssembly(this IServiceCollection, Action<CompiledAssemblyApiOptions>)Package
Convenience overload: registers under thePennington.ApiMetadata.Reflection"default"name for sites documenting a single library.AddApiMetadataFromCompiledAssemblyIServiceCollection AddApiMetadataFromCompiledAssembly(this IServiceCollection, string, Action<CompiledAssemblyApiOptions>)Package
RegistersPennington.ApiMetadata.ReflectionCompiledAssemblyApiMetadataProvideras a keyedIApiMetadataProviderundername. Call once per library you want to document — each call builds its ownMetadataLoadContextand xmldoc index scoped to the suppliedAssemblyDirectories. The Roslyn-independentIXmlDocParser/IXmlDocHtmlRenderershared services are registered once (idempotent).AddApiMetadataFromRoslynIServiceCollection AddApiMetadataFromRoslyn(this IServiceCollection, string = …, Action<ApiReferenceOptions>? = …)Package
RegistersPennington.RoslynRoslynApiMetadataProvideras a keyedIApiMetadataProviderundername. Call once per named reference tree. RequiresAddPenningtonRoslynto have been called first with a configuredSolutionPath, since the provider reads the live workspace.AddApiReferenceIServiceCollection AddApiReference(this IServiceCollection, string = …, Action<ApiReferenceRegistrationOptions>? = …)Package
Registers one named API-reference tree. Call once per library you want to document. Each call pairs with a matchingPennington.DocSite.ApiAddApiMetadataFrom*(name, …)provider registration and publishes its type pages at the configuredRoutePrefix.AddBlogSiteIServiceCollection AddBlogSite(this IServiceCollection, Func<BlogSiteOptions>)Package
Registers BlogSite services with the provided options.Pennington.BlogSiteAddDocSiteIServiceCollection AddDocSite(this IServiceCollection, Func<DocSiteOptions>)Package
Registers DocSite services with the provided options.Pennington.DocSiteAddFileWatched<T>IServiceCollection AddFileWatched<T>(this IServiceCollection)Package
Register a concrete service whose instance is managed byPenningtonFileWatchDependencyFactory.AddFileWatched<TService, TImplementation>IServiceCollection AddFileWatched<TService, TImplementation>(this IServiceCollection)Package
Register a service whose instance is managed byPenningtonFileWatchDependencyFactory. The factory (singleton) recreates the instance when watched files change. The service (transient) always returns the current instance from the factory.AddLlmsSubtreeIServiceCollection AddLlmsSubtree(this IServiceCollection, LlmsSubtree)Package
Registers aPenningtonLlmsSubtreeso all leaves underRoutePrefixget split out into a dedicated{RoutePrefix}llms.txt. Multiple registrations are allowed; programmatic registrations override_llms.yaml-discovered subtrees with the same prefix.AddMonorailCssIServiceCollection AddMonorailCss(this IServiceCollection, Func<IServiceProvider, MonorailCssOptions>? = …)Package
Registers MonorailCSS services including the CSS class collector and stylesheet generator.Pennington.MonorailCssAddPenningtonIServiceCollection AddPennington(this IServiceCollection, Action<PenningtonOptions>)Package
Register all Pennington services.PenningtonAddPenningtonRoslynIServiceCollection AddPenningtonRoslyn(this IServiceCollection, Action<RoslynOptions>? = …)Package
Add Roslyn-based code analysis and highlighting.Pennington.RoslynAddPenningtonTuiIServiceCollection AddPenningtonTui(this IServiceCollection, Action<PenningtonTuiOptions>? = …)Package
Register the dev-time TUI dashboard. When the host is launched in build mode (first command-line argument isPennington.Tuibuild), the hosted service no-ops and the build runs exactly as without this package.AddSpaNavigationIServiceCollection AddSpaNavigation(this IServiceCollection, Action<SpaNavigationOptions>? = …)Package
Register SPA navigation services.Pennington
WebApplication and endpoint extensions
Middleware and endpoint wiring. Ordering within a Use* call chain is load-bearing; see each method's xmldoc for the invariant.
RunBlogSiteAsyncTask RunBlogSiteAsync(this WebApplication, string[])Package
Runs the BlogSite: either serves the app or performs a static build, based on command-line args.Pennington.BlogSiteRunDocSiteAsyncTask RunDocSiteAsync(this WebApplication, string[])Package
Runs the DocSite: either serves the app or performs a static build, based on command-line args.Pennington.DocSiteRunOrBuildAsyncTask RunOrBuildAsync(this WebApplication, string[])Package
Run in dev mode or build static site.PenningtonUseBlogSiteWebApplication UseBlogSite(this WebApplication)Package
Wires BlogSite middleware, Razor components, and RSS endpoint into the request pipeline.Pennington.BlogSiteUseDocSiteWebApplication UseDocSite(this WebApplication)Package
Wires DocSite middleware and Razor components into the request pipeline.Pennington.DocSiteUseMonorailCssWebApplication UseMonorailCss(this WebApplication, string = …)Package
Maps the MonorailCSS stylesheet endpoint and scans configured content files for CSS classes.Pennington.MonorailCssUsePenningtonWebApplication UsePennington(this WebApplication)Package
Configure the Pennington middleware pipeline.PenningtonUsePenningtonLiveReloadWebApplication UsePenningtonLiveReload(this WebApplication)Package
Adds live reload WebSocket support for development. Skipped during static build (seePenningtonPenningtonBuildMode).UsePenningtonLocaleRoutingWebApplication UsePenningtonLocaleRouting(this WebApplication)Package
Adds locale detection and URL path rewriting middleware. Must be calledPenningtonMapRazorComponentsso that Blazor routing sees the locale-stripped path (e.g.,/gen-z/schedulebecomes/schedule). Called automatically byUsePenningtonwhen it hasn't been called yet, but at that point it is too late for Blazor endpoint routing. Sites that use@pagedirectives with locale prefixes must call this explicitly.
UseSpaNavigationIEndpointRouteBuilder UseSpaNavigation(this IEndpointRouteBuilder)Package
Map the SPA data endpoint.Pennington
Host runtime helpers
Entry points that dispatch between dev-serve and static-build based on args[0]. Dev and build share one rendering pipeline; the build branch calls app.StartAsync(), resolves OutputGenerationService, crawls the running host via HTTP, and writes to OutputOptions.OutputDirectory.
See RunOrBuildAsync on the PenningtonExtensions type page for the full dispatch contract.
Example
A complete DocSite host wiring all three layers — AddDocSite, UseDocSite, RunDocSiteAsync — in their canonical call order.
using Pennington.DocSite;
var builder = WebApplication.CreateBuilder(args);
// Swap the bare `AddPennington` host for the DocSite template. `AddDocSite`
// wires the full documentation experience on top of Pennington core — a
// Blazor-rendered layout with sidebar navigation, header, search surface,
// outline nav, dark-mode toggle — driven entirely from `DocSiteOptions`.
builder.Services.AddDocSite(() => new DocSiteOptions
{
SiteTitle = "Scaffold Docs",
Description = "A minimal DocSite scaffold showing AddDocSite and area routing.",
GitHubUrl = "https://github.com/usepennington/pennington",
HeaderContent = """<a href="/">Scaffold Docs</a>""",
FooterContent = """<footer class="mt-16 py-8 text-center text-sm text-base-500">Built with Pennington DocSite.</footer>""",
// Each area maps to a top-level folder under `Content/` and to a URL
// prefix. The sidebar renders an area selector when more than one is
// configured and only shows the TOC for the active area.
Areas =
[
new ContentArea("Guides", "guides"),
new ContentArea("Reference", "reference"),
],
});
var app = builder.Build();
// `UseDocSite` mounts locale routing, antiforgery, static files, Razor
// component routing (`Pages.razor` owns `/{*fileName:nonfile}`), MonorailCSS,
// SPA navigation, and the core Pennington middleware in the right order.
app.UseDocSite();
// `RunDocSiteAsync` delegates to `RunOrBuildAsync`, so `dotnet run` serves live
// and `dotnet run -- build <baseUrl> <outputDir>` generates static HTML. Both
// positional args are optional (defaults: `/` and `output`).
await app.RunDocSiteAsync(args);
The same three-call shape holds for every template: Add* builds the service graph, Use* mounts the middleware and endpoints, Run*Async reads args and either serves or builds.
See also
- Reference: CLI and build arguments
- Reference:
PenningtonOptions - Reference:
DocSiteOptions - Background: Dev mode and build mode share one code path