{"metadata":{"generatedAtUtc":"2026-05-15T04:24:12.5818493\u002B00:00","version":"1","engine":"minisearch"},"documents":[{"id":"","path":"/docs","title":"AppSurface","summary":"AppSurface gives .NET teams a modular startup pipeline for web, console, and distributed apps. Start with the pillar you need, then drill into concrete examples and API reference.","headings":["Vision","Key Design Goals","Caching Conventions","Project Structure","Packages","Core","Console","Web","CLI","Dependency","Aspire","Getting started","Release notes and upgrade policy","Feedback and contributing","Examples","License"],"bodyText":"AppSurface \u26A0\uFE0F Under Construction: This library is actively being developed and is not intended for production use yet. Monorepo for the ForgeTrust.AppSurface projects ForgeTrust.AppSurface is a collection of .NET libraries designed to provide a lightweight, modular startup pipeline for both console and web applications. If you are deciding which package to install first, start with the AppSurface v0.1 package chooser . Vision The primary vision of AppSurface is to simplify application bootstrapping by encouraging composition through small, focused modules . Instead of monolithic startup classes or scattered configuration logic, AppSurface allows developers to encapsulate features into reusable modules that handle: Dependency Injection (DI) registration Host configuration Application-specific startup logic This approach aims to: Share cross-cutting concerns between different application types (e.g., sharing logging or database setup between a Web API and a background Console worker). Keep applications minimal , with infrastructure heavily decoupled from business logic. Provide consistency in how applications are initialized and configured, regardless of whether they are web or console apps. Key Design Goals Modularity : Everything should be a module that does one thing well. Take what you need and don\u0027t get burdened by what you don\u0027t. Consistency : A unified AppSurfaceStartup pipeline for different project types. Flexibility : Open for integration with external libraries (Autofac, OpenApi, etc.) and stick to framework provided abstractions where possible. Performance : Designed to have minimal overhead on the application startup and execution. Ease of Use : Simple APIs and clear patterns to make getting started frictionless. Convention over Configuration : Sensible defaults are provided so only minimal configuration is required. Secure By Default : Security best practices are applied automatically where appropriate. Caching Conventions Use IMemo for application and service-layer caching (for example, web modules and domain services). Use direct IMemoryCache only inside caching infrastructure (the ForgeTrust.AppSurface.Caching package) or framework integration points where IMemo cannot be injected. If a module depends on AppSurfaceCachingModule , do not call AddMemoryCache() again in that module. Prefer one cache boundary per data snapshot. In RazorDocs, DocAggregator owns both docs aggregation and search-index payload caching so downstream controllers consume one shared snapshot. Project Structure Packages AppSurface v0.1 package chooser - the generated install map for direct-install packages, support/runtime packages, and proof-host surfaces. Core ForgeTrust.AppSurface.Core \u2013 Core abstractions for defining modules and starting an application via AppSurfaceStartup and StartupContext . Console ForgeTrust.AppSurface.Console \u2013 Helpers for building command line apps with CliFx including a CriticalService -based command runner and helpers for configuring services. Web ForgeTrust.AppSurface.Web \u2013 Bootstraps ASP.NET Core apps, lets modules register middleware and endpoints, and includes conventional browser status pages plus opt-in production 500 pages. ForgeTrust.AppSurface.Web.OpenApi \u2013 Optional module that adds OpenAPI generation using AddEndpointsApiExplorer and WithOpenApi . ForgeTrust.RazorWire \u2013 Adds reactive Razor-based streaming, islands, and CDN-default export tooling for server-rendered web apps. ForgeTrust.AppSurface.Docs \u2013 Reusable Razor Class Library package that serves harvested source docs with section-first landing, sidebar, search, built-in trust plus contributor-provenance details, and optional published-version archive surfaces. ForgeTrust.AppSurface.Docs.Standalone \u2013 Thin export host for exporting or serving RazorDocs as an application. ForgeTrust.AppSurface.Web.Scalar \u2013 Optional module that serves the Scalar API reference UI and depends on the OpenAPI module. CLI ForgeTrust.AppSurface.Cli \u2013 Public appsurface command-line tool, including the appsurface docs RazorDocs preview workflow. Dependency ForgeTrust.AppSurface.Dependency.Autofac \u2013 Optional integration with the Autofac IoC container so modules can participate in Autofac service registration. Aspire ForgeTrust.AppSurface.Aspire \u2013 Integration with .NET Aspire to provide a modular approach to defining distributed applications and service defaults. These packages are designed to work together so that features can be shared across different application types while maintaining a consistent startup approach. Getting started If you want to see value first, run the web hello world: Bash dotnet run --project examples/web-app -- --port 5055 Then, from another terminal, prove the running endpoint: Bash curl http://127.0.0.1:5055 Expected response: Plain text Hello World from the root! That example is the smallest concrete path through ForgeTrust.AppSurface.Web : a root module, one mapped endpoint, and the AppSurface startup pipeline doing the hosting work. If you are evaluating packages from your own app project rather than running this repo, start with the generated package chooser in packages/README.md . Use the package matrix to pick the module your app actually needs, then run the matching install command from your app project, for example: Bash dotnet add package ForgeTrust.AppSurface.Web --project \u003C path-to-your-app.csproj \u003E Add optional modules only when the generated chooser points you to them. For contributor verification, build the solution: Bash dotnet build dotnet test --no-build Run merged solution coverage (product assemblies only): Bash ./scripts/coverage-solution.sh This command: Runs each solution test project. Collects coverage only for ForgeTrust.AppSurface.* modules. Excludes test modules ( *.Tests and *.IntegrationTests ) from coverage. Produces one merged Cobertura file at TestResults/coverage-merged/coverage.cobertura.xml . Writes a summary to TestResults/coverage-merged/summary.txt . Check out the examples to see how modules are composed in practice: Bash dotnet run --project examples/console-app dotnet run --project examples/web-app dotnet run --project examples/razorwire-mvc/RazorWireWebExample.csproj For the intentional validation-failure shape, run dotnet run --project examples/config-validation . The RazorWire MVC example includes a failed-form UX page at /Reactivity/FormFailures that shows server-handled validation, development anti-forgery diagnostics, default fallback rendering, and consumer styling hooks. Release notes and upgrade policy AppSurface is preparing to release the entire monorepo in unison. The public release contract now lives in the repository so teams can see what is queued for the next version, how pre-1.0 changes are handled, and where future migration notes will live. Package chooser - the generated first-install map for web, console, Aspire, and optional package add-ons. Release hub - start here for the narrative release surface. Unreleased proof artifact - the living notes for the next coordinated version. Changelog - the compact ledger for tagged and in-flight changes. Pre-1.0 upgrade policy - the stability and migration contract before v1.0.0 . Contribution and release entry rules - how PR titles and unreleased entries feed the release surface. Feedback and contributing AppSurface uses GitHub issue forms to keep bug reports, feature requests, and docs/developer-experience feedback concrete enough to reproduce or evaluate. If an example, README, quickstart, or package API leaves you stuck, start with the contribution guide , choose an issue template , and file the form that matches the problem. Use docs/DX feedback for confusing guidance, missing concepts, broken links, snippet drift, or first-run friction. Use feature requests for focused product capabilities, API shapes, workflows, or examples. Use bug reports when runtime behavior, generated output, or package APIs do something unexpected. Do not file suspected vulnerabilities, leaked secrets, or exploit details in public issues; follow the security policy instead. Examples The examples directory contains sample applications that demonstrate how to use this project. Console app example \u2013 builds a simple command line application using CliFx for command definitions. Web app example \u2013 shows a minimal ASP.NET Core app that composes middleware and endpoints from modules. Config validation example \u2013 shows scalar validation on a strongly typed config wrapper and the startup failure shape. License AppSurface is licensed under the Polyform Small Business License 1.0.0 . Free for individuals and businesses with fewer than 100 people and under $1,000,000 USD prior-year revenue (inflation-adjusted). Larger companies require a commercial license.","snippet":"AppSurface \u26A0\uFE0F Under Construction: This library is actively being developed and is not intended for production use yet. Monorepo for the ForgeTrust.AppSurface projects ForgeTrust.AppSurface is a collection of .NET...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Start Here","publicSection":"start-here","publicSectionLabel":"Start Here","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Start Here","AppSurface"],"sourcePath":"README.md"},{"id":"agents","path":"/docs/agents","title":"AGENTS.md","summary":"These guidelines apply to all changes made in this repository.","headings":["Modification Guidelines","Documentation","Tests","Code Quality"],"bodyText":"AGENTS.md Modification Guidelines These guidelines apply to all changes made in this repository. Documentation Fully document all API surface areas affected by a change, including both external and internal APIs. Treat documentation as part of the feature, not as optional follow-up work. Include reference content that explains the API shape, behavior, defaults, constraints, and expected usage. Include decision content that explains why an API exists, when it should be used, and when a different approach is the better choice. Include pitfall content that calls out sharp edges, ordering requirements, surprising behavior, and common mistakes. Update package-level and repository-level documentation when a change affects discoverability or adoption, not just inline XML comments. Tests Aim for nearly 100% branch verification coverage, especially in changed code and critical execution paths. Test both success paths and failure or edge-case branches. Test behavior through public APIs and internal APIs that are intentionally exposed for testing. Do not use reflection in tests to access private members. If code is difficult to verify without reflection, improve the design or add an appropriate test seam instead of breaking encapsulation. Add regression tests for bug fixes. When practical, verify solution-level coverage with ./scripts/coverage-solution.sh . Code Quality Run code formatting before pushing changes. Follow the repository .editorconfig and established formatting conventions rather than personal preferences. Resolve all compiler, analyzer, and documentation warnings introduced by a change before pushing. Prefer changes that reduce existing warnings in touched areas instead of working around them or suppressing them without strong justification. Follow current C# and .NET best practices so code is clear, idiomatic, and maintainable.","snippet":"AGENTS.md Modification Guidelines These guidelines apply to all changes made in this repository. Documentation Fully document all API surface areas affected by a change, including both external and internal APIs....","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","AGENTS.md"],"sourcePath":"AGENTS.md"},{"id":"aspire","path":"/docs/aspire","title":"Aspire Projects","summary":"Modular integration for .NET Aspire distributed applications.","headings":["Contents"],"bodyText":"Aspire Projects Modular integration for .NET Aspire distributed applications. Contents ForgeTrust.AppSurface.Aspire \u2013 Core Aspire integration. ForgeTrust.AppSurface.Aspire.Tests \u2013 Tests for Aspire components. \uD83C\uDFE0 Back to Root","snippet":"Aspire Projects Modular integration for .NET Aspire distributed applications. Contents ForgeTrust.AppSurface.Aspire \u2013 Core Aspire integration. ForgeTrust.AppSurface.Aspire.Tests \u2013 Tests for Aspire components. \uD83C\uDFE0 Back...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","Aspire Projects"],"sourcePath":"Aspire/README.md"},{"id":"aspire/forgetrust.appsurface.aspire","path":"/docs/aspire/forgetrust.appsurface.aspire","title":"ForgeTrust.AppSurface.Aspire","summary":".NET Aspire integration for the AppSurface ecosystem.","headings":["Overview","Installation","Usage"],"bodyText":"ForgeTrust.AppSurface.Aspire .NET Aspire integration for the AppSurface ecosystem. Overview ForgeTrust.AppSurface.Aspire provides a modular way to define distributed applications using .NET Aspire. It allows you to encapsulate service defaults and resource registrations into modules. Installation Bash dotnet add package ForgeTrust.AppSurface.Aspire Usage Use AspireApp to start your Aspire AppHost: C# await AspireApp \u003C MyHostModule \u003E . RunAsync ( args ) ; \uD83D\uDCC2 Back to Aspire List | \uD83C\uDFE0 Back to Root","snippet":"ForgeTrust.AppSurface.Aspire .NET Aspire integration for the AppSurface ecosystem. Overview ForgeTrust.AppSurface.Aspire provides a modular way to define distributed applications using .NET Aspire. It allows you to...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Aspire"],"sourcePath":"Aspire/ForgeTrust.AppSurface.Aspire/README.md"},{"id":"caching/forgetrust.appsurface.caching","path":"/docs/caching/forgetrust.appsurface.caching","title":"ForgeTrust.AppSurface.Caching","summary":"Caching primitives for AppSurface applications built on top of \u0060Microsoft.Extensions.Caching.Memory\u0060.","headings":["Overview","Key Types","Usage","Notes"],"bodyText":"ForgeTrust.AppSurface.Caching Caching primitives for AppSurface applications built on top of Microsoft.Extensions.Caching.Memory . Overview This package provides a small, focused caching layer for AppSurface modules. It is designed for scenarios where you want consistent memoization behavior, cache policies, and a module you can register into the AppSurface startup pipeline. Key Types AppSurfaceCachingModule : Registers the package services into the AppSurface module system. IMemo / Memo : Memoization helpers for caching computed values and async results. CachePolicy : A simple policy object for configuring expiration and cache behavior. Usage Register the module in your application and inject IMemo where you want to cache repeated work: C# public sealed class MyModule : AppSurfaceCachingModule { } Use memoization for expensive or repeated lookups: C# var result = await memo . GetOrCreateAsync ( \u0022 docs:index \u0022 , ( ) =\u003E LoadDocsAsync ( ) , new CachePolicy ( ) ) ; Notes The package builds on Microsoft.Extensions.Caching.Memory , so it works well for in-process application caching. This package is intentionally lightweight and fits best when you want simple, application-level caching rather than a distributed cache abstraction.","snippet":"ForgeTrust.AppSurface.Caching Caching primitives for AppSurface applications built on top of Microsoft.Extensions.Caching.Memory . Overview This package provides a small, focused caching layer for AppSurface modules....","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Caching"],"sourcePath":"Caching/ForgeTrust.AppSurface.Caching/README.md"},{"id":"changelog","path":"/docs/changelog","title":"Changelog","summary":"Compact ledger for coordinated AppSurface releases across packages, CLI tooling, examples, and docs-facing behavior.","headings":["Reading guide","Unreleased","Added","Changed","Migration","No tagged releases yet"],"bodyText":"Changelog This changelog is the compact release ledger for AppSurface. The monorepo ships in unison, so each tagged version covers packages, CLI tooling, examples, and docs-facing behavior from this repository together. Reading guide Unreleased tracks the next coordinated version and points to the living release note. Future tagged sections will use the shape ## x.y.z - YYYY-MM-DD . Every tagged section will link to a matching narrative release note in releases/ . Breaking or behavior-changing updates must record migration guidance here and in the matching release note. Unreleased Narrative release note: Upcoming release note Upgrade policy: Pre-1.0 upgrade policy Authoring workflow: Release authoring checklist Added AppSurface now has a planned appsurface .NET tool surface. Its first verb is appsurface docs , which runs RazorDocs preview workflows through the existing standalone docs host instead of minting a separate razordocs CLI. AppSurface Web now has a startup watchdog that fails fast when a web host stalls before Kestrel starts listening; appsurface docs exposes the same guard through --startup-timeout-seconds . RazorDocs and RazorWire runtime assets are now embedded into their assemblies and served through endpoint fallbacks, so packaged CLI hosts can serve docs UI assets without relying on static web asset manifests. AppSurface now has a repo-level release contract: a public release hub, an unreleased proof artifact, a pre-1.0 upgrade policy, and a tagged-release template for future versioned notes. RazorWire now has a package-level generated UI design contract that defines ownership scope, data-attribute and CSS custom-property styling surfaces, accessibility expectations, override levels, and anti-patterns for package-owned UI. RazorDocs pages can now render a top-of-page trust bar from structured metadata so release notes and upgrade guidance can show status, safety context, and provenance without custom page code. RazorDocs now supports metadata-driven page wayfinding: harvested outlines, explicit proof-path previous/next links, related pages, and sidebar anchor navigation. RazorDocs now exposes DocAggregator.GetHarvestHealthAsync(...) plus structured harvest health models so hosts can distinguish healthy, empty, degraded, and all-failed source harvest snapshots without parsing logs. RazorWire forms now have convention-based failed-submission UX with default form-local fallbacks, server helpers for handled validation errors, development anti-forgery diagnostics, runtime events, and sample coverage. The root README now includes a single hello-world web quickstart with an explicit local port and a concrete expected response. AppSurface now ships GitHub issue templates for bug reports and documentation feedback. AppSurface Config now supports first-class scalar value validation on Config\u003CT\u003E and ConfigStruct\u003CT\u003E wrappers with ConfigValueNotEmpty , ConfigValueRange , ConfigValueMinLength , and a ValidateValue override for custom rules. Changed AppSurface now treats the whole monorepo as one coordinated release surface. Packages, CLI tools, examples, and docs-facing behavior all roll into the same upcoming version. Pull requests are expected to use Conventional Commits titles and to update releases/unreleased.md unless maintainers explicitly opt out. Markdown-only changes on main now trigger the build-and-export workflow so release-note and policy updates publish with the docs surface. RazorWire CLI validation errors now include a concrete next command and razorwire export --help hint so failed exports are easier to recover from. RazorWire CLI export now defaults to CDN-safe output: managed internal links, frames, scripts, stylesheets, images, \u003Cimg\u003E and \u003Csource\u003E srcset , conventional 404.html , and CSS url(...) references rewrite to emitted static artifacts, with --mode hybrid available for extensionless server-routed deployments. Tailwind development watch mode now logs a warning, not a startup error, when the standalone CLI is unavailable and the app can continue serving existing CSS. RazorDocs search now keeps failure recovery markup out of the active search shell until the index actually fails to load. The RazorWire MVC sample counter button now has an accessible name while preserving the compact icon-only UI. RazorDocs source-path, canonical-path, fragment, and docs-root-prefixed lookups now share one resolver across page details, landing curation, related-page links, and search fallback links. RazorDocs landing curation now renders reader-intent featured_page_groups instead of one flat featured list. RazorDocs authored Markdown pages now use a tighter prose layout while generated API pages keep the wider reference treatment. RazorDocs now redirects public Markdown source-shaped requests such as /docs/packages/README.md to the clean canonical route instead of returning a 404. The PackageIndex generator now has a successful --help / -h path with command and option guidance instead of a bare usage failure. The conventional browser 404 page now favors user recovery, including documentation search for missing docs routes and a home link for other missing pages. AppSurface Web now generalizes conventional browser status pages to empty HTML 401 , 403 , and 404 responses with BrowserStatusPageMode , BrowserStatusPageModel , preview routes, and status-specific Razor override paths. Static export still writes only 404.html ; conventional production 500 exception pages are tracked separately in issue #224. StartupContext.ApplicationName is now treated as a display label while IHostEnvironment.ApplicationName stays assembly-backed for static web asset manifest discovery. Migration AppSurface has not cut v0.1.0 yet, so there is no tagged migration guide today. Before v0.1.0 , any breaking or behavior-changing update should record provisional guidance in releases/unreleased.md and move finalized steps into the tagged release note once the version ships. Existing rw-active forms opt into failed-form request markers and automatic fallback UI by default. Set options.Forms.EnableFailureUx = false , options.Forms.FailureMode = RazorWireFormFailureMode.Manual , or per-form data-rw-form-failure=\u0022off\u0022 if an app already owns all failure rendering. Existing RazorWire CLI export users who depended on extensionless internal URLs should pass --mode hybrid ; the default now rewrites exporter-managed URLs for plain static/CDN hosting and fails CDN validation when required frame or asset artifacts cannot be emitted. RazorDocs authors using featured_pages should migrate to featured_page_groups ; the old flat field now logs a warning and no longer renders. Code that expected custom AppSurface labels from IHostEnvironment.ApplicationName should use StartupContext.ApplicationName ; host environment application names now remain tied to assembly identity so ASP.NET static web assets continue to resolve. Web apps with custom conventional 404 overrides should replace NotFoundPageModel with BrowserStatusPageModel . The old ConventionalNotFoundPageMode , NotFoundPageMode , UseConventionalNotFoundPage() , and DisableNotFoundPage() API names have moved to the BrowserStatusPage* naming surface before the first public tag. RazorDocs hosts that need operational status for source-backed docs should call DocAggregator.GetHarvestHealthAsync(...) and branch on DocHarvestHealthStatus and diagnostic codes instead of scraping warning or critical log messages. No tagged releases yet AppSurface is still defining its first release boundary. The first tagged section will be added when the project is ready to cut v0.1.0 .","snippet":"Changelog This changelog is the compact release ledger for AppSurface. The monorepo ships in unison, so each tagged version covers packages, CLI tooling, examples, and docs-facing behavior from this repository...","pageType":"release-log","pageTypeLabel":"Release Log","pageTypeVariant":"neutral","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Releases","publicSection":"releases","publicSectionLabel":"Releases","isSectionLanding":false,"order":20,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Releases","Changelog"],"sourcePath":"CHANGELOG.md"},{"id":"cli/forgetrust.appsurface.cli","path":"/docs/cli/forgetrust.appsurface.cli","title":"AppSurface CLI","summary":"The **AppSurface CLI** is the command-line home for repository-level AppSurface workflows. It is packaged as a .NET tool with the command name \u0060appsurface\u0060.","headings":["Commands","appsurface docs","Development"],"bodyText":"AppSurface CLI The AppSurface CLI is the command-line home for repository-level AppSurface workflows. It is packaged as a .NET tool with the command name appsurface . The first public verb is docs , which replaces the earlier standalone razordocs preview --repo . idea with an AppSurface-owned command: Bash appsurface docs --repo . --urls http://127.0.0.1:5189 appsurface docs runs the same RazorDocs standalone host used by CI and integration tests. It forwards RazorDocs configuration into that host instead of duplicating harvesting, routing, static web asset, or MVC setup in the CLI. Commands appsurface docs Preview RazorDocs for a repository checkout. Bash appsurface docs --repo . --port 5189 Options: --repo , -r : Repository root to preview. Defaults to the current directory. --urls , -u : Explicit host URL binding, such as http://127.0.0.1:5189 . --port , -p : AppSurface Web port shortcut forwarded to the RazorDocs host. --strict : Enables RazorDocs:Harvest:FailOnFailure=true , which fails startup when every configured harvester fails. --route-root : Route-family root for version and archive routes. --docs-root : Live docs preview root. --environment , -e : Host environment forwarded to the RazorDocs host. --startup-timeout-seconds : Seconds to wait for the web host to start before failing fast. Defaults to 30 ; use 0 to disable while investigating intentional pre-bind delays. appsurface docs preview is an alias for the same behavior, kept so the old deferred shape maps cleanly to the new AppSurface command family. Development Run the tool from source while developing: Bash dotnet run --project Cli/ForgeTrust.AppSurface.Cli -- docs --repo . --urls http://127.0.0.1:5189 Use --strict for CI-like validation when an all-failed harvest should stop the preview before the host begins serving.","snippet":"AppSurface CLI The AppSurface CLI is the command-line home for repository-level AppSurface workflows. It is packaged as a .NET tool with the command name appsurface . The first public verb is docs , which replaces the...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","AppSurface CLI"],"sourcePath":"Cli/ForgeTrust.AppSurface.Cli/README.md"},{"id":"concepts/glossary","path":"/docs/concepts/glossary","title":"AppSurface Glossary","summary":"Define the core AppSurface terms used by package docs, examples, and the evaluator path.","headings":["AppSurfaceStartup","Root Module","Dependent Module","Host Module","StartupContext","Package Module","Web Module","Console Startup","Package Chooser"],"bodyText":"AppSurface Glossary This glossary defines the terms needed to read the AppSurface package docs and examples. Package READMEs remain the source of truth for full API behavior. AppSurfaceStartup AppSurfaceStartup is the startup pipeline that composes modules on top of the .NET Generic Host. Use the package-specific entry points, such as WebApp\u003CTModule\u003E , unless you need deeper host customization. Root Module The root module is the module type passed to an AppSurface entry point. It is the starting point for module composition. Example: C# await WebApp \u003C ExampleModule \u003E . RunAsync ( args ) ; ExampleModule is the root module. Dependent Module A dependent module is another module registered by a module through RegisterDependentModules . Use dependencies when one module needs another module\u0027s services, options, middleware, endpoints, or host behavior. Host Module A host module participates in .NET host setup through the core module lifecycle. IAppSurfaceHostModule is the core contract for modules that can configure services and host behavior. StartupContext StartupContext carries startup metadata such as the app label, host application identity, application discovery assembly, environment, and console output mode. Keep display labels and host identity separate. Static web assets use host identity, not the label you want to show to users. Package Module A package module is an AppSurface module shipped by a package, such as the Web, Console, Aspire, or optional web modules. Install package modules only when the package chooser says they match the app. Web Module A web module participates in ASP.NET Core startup through IAppSurfaceWebModule . It can configure web options, register middleware, and map endpoints. The base web package is ForgeTrust.AppSurface.Web . Console Startup Console startup is the AppSurface path for CLI commands and worker-style processes. Start with the Console package docs when the app is command-oriented instead of web-oriented. Package Chooser The package chooser is the generated install map for the coordinated AppSurface package family. Use it before adding optional modules. Read it here: AppSurface v0.1 package chooser","snippet":"AppSurface Glossary This glossary defines the terms needed to read the AppSurface package docs and examples. Package READMEs remain the source of truth for full API behavior. AppSurfaceStartup AppSurfaceStartup is the...","pageType":"glossary","pageTypeLabel":"Glossary","pageTypeVariant":"glossary","audience":null,"component":null,"aliases":["AppSurfaceStartup","root module","StartupContext","host module"],"keywords":["IAppSurfaceModule","IAppSurfaceHostModule","WebApp","package chooser"],"status":null,"navGroup":"Concepts","publicSection":"concepts","publicSectionLabel":"Concepts","isSectionLanding":false,"order":40,"sequenceKey":null,"canonicalSlug":null,"relatedPages":["ForgeTrust.AppSurface.Core/README.md","Web/ForgeTrust.AppSurface.Web/README.md"],"breadcrumbs":["Concepts","AppSurface Glossary"],"sourcePath":"concepts/glossary.md"},{"id":"config/forgetrust.appsurface.config","path":"/docs/config/forgetrust.appsurface.config","title":"ForgeTrust.AppSurface.Config","summary":"Strongly typed configuration primitives for AppSurface applications.","headings":["Overview","Key Types","Usage","Configuration Audit Reports","Provenance Behavior","Redaction Defaults","Audit Pitfalls","Environment Overrides","Override Pitfalls","Validation","Required Key Presence","Scalar Value Validation","Recursive Validation","Pitfalls","Example","Notes"],"bodyText":"ForgeTrust.AppSurface.Config Strongly typed configuration primitives for AppSurface applications. Overview This package provides the configuration layer for AppSurface modules. It combines file-based configuration, environment-aware providers, and strongly typed configuration objects so modules can consume configuration without hard-coding access patterns throughout the codebase. Key Types AppSurfaceConfigModule : Registers the configuration services for an AppSurface application. IConfigManager : Central access point for resolving configuration values. IConfigProvider : Abstraction for reading configuration from a source. FileBasedConfigProvider : Loads configuration from files. IConfigAuditReporter : Builds source-aware configuration audit reports for known config entries. ConfigAuditTextRenderer : Renders a safe, human-readable audit report from the structured model. Config\u003CT\u003E / ConfigStruct\u003CT\u003E : Base types for strongly typed configuration values. ConfigKeyAttribute : Associates a configuration type or property with a specific key. ConfigKeyRequiredAttribute : Requires a config wrapper to resolve a provider or default value during startup. ConfigValueNotEmptyAttribute : Validates that a resolved scalar string or Guid value is not empty. ConfigValueRangeAttribute : Validates that a resolved scalar int or double value is within an inclusive range. ConfigValueMinLengthAttribute : Validates that a resolved scalar string value meets a minimum length. ConfigurationValidationException : Startup-time exception that reports object DataAnnotations and scalar validation failures for a resolved config value. ConfigurationValidationFailure : Structured validation failure details for logging and tests. Usage Register the module and model your settings with strongly typed config objects: C# public sealed class MyModule : AppSurfaceConfigModule { } Define configuration models: C# public sealed class DocsPathConfig : Config \u003C string \u003E { } Resolve them through the configuration services used by your module or application startup flow. Install the package from an application project with: Bash dotnet add package ForgeTrust.AppSurface.Config --project \u003C path-to-your-app.csproj \u003E Configuration Audit Reports Use IConfigAuditReporter when an operator or maintainer needs to answer: Plain text What does this app believe its configuration is, and why? The reporter returns a structured ConfigAuditReport for an environment. The report includes provider order, known configuration entries, source records, entry states, diagnostics, and display-safe values. A known entry is either a discovered Config\u003CT\u003E / ConfigStruct\u003CT\u003E wrapper or a key registered explicitly with AddConfigAuditKey\u003CT\u003E() . C# var report = auditReporter . GetReport ( \u0022 Staging \u0022 ) ; var text = textRenderer . Render ( report ) ; Explicit registrations are useful for keys that are read directly through IConfigManager instead of a wrapper: C# services . AddConfigAuditKey \u003C string \u003E ( \u0022 Billing.Endpoint \u0022 ) ; Audit entry states are intentionally small: State Meaning Resolved A provider supplied the value without member-level mixed provenance. PartiallyResolved An object value has a base source plus one or more member-level environment patches. Defaulted No provider supplied a value, but the config wrapper default supplied one. Missing No provider value and no default resolved for the known entry. Invalid A provider value, patch, or wrapper validation result was invalid. Provenance Behavior Environment variables are checked before lower-priority providers, matching normal DefaultConfigManager resolution. File values report FileBasedConfigProvider , the file path, and the config path. Direct environment values report the concrete environment variable name. Object-valued entries can include child entries when the final value combines a file base with environment child patches: Plain text MyApp.Settings Source: FileBasedConfigProvider appsettings.Staging.json :: MyApp.Settings Children: MyApp.Settings.Database.Port = 6543 Source: Environment variable MYAPP__SETTINGS__DATABASE__PORT The report is observational. Environment patch diagnostics trace patches against a cloned value so asking for an audit report does not mutate the provider object being inspected. Redaction Defaults Audit reports are redacted by default before renderers see values. Sensitive-looking paths, keys, and environment variable names render as [redacted] . The built-in fragments include password , secret , token , apikey , key , connectionstring , credential , and private . Redaction is deliberately conservative. It does not expose string lengths, sensitive collection counts, or sensitive nested values. Source metadata remains visible unless a provider marks the source metadata itself as sensitive. This keeps reports safe to paste into support issues while still showing where a value came from. Audit Pitfalls Audit reports cover AppSurface-known entries, not every raw process environment variable or every unused file key. Provider-discovered raw key enumeration is intentionally separate from the first audit surface. File origins include file path and config path. Line and column origins are not part of the first report. Validation diagnostics name keys and rules; they do not include attempted secret values. A direct environment object value replaces the whole object, while child environment variables produce member-level patch provenance. Environment Overrides Environment variables override file-based providers. AppSurface supports both the legacy flattened shape and the hierarchical double-underscore shape commonly used by .NET configuration: Plain text PRODUCTION_APP_SETTINGS APP_SETTINGS PRODUCTION__APP__SETTINGS APP__SETTINGS Use a direct value when one environment variable should replace the whole requested config value. For object-valued config, the direct value is parsed as JSON: Plain text APP__SETTINGS={\u0022Database\u0022:{\u0022Host\u0022:\u0022db.example\u0022,\u0022Port\u0022:5432}} Use child variables when deployment needs to override one member without replacing the rest of an options object loaded from JSON files, or when the target type can be built from child variables alone: Plain text APP__SETTINGS__DATABASE__PORT=6543 When App.Settings is resolved as an object, AppSurface first looks for a direct environment value. If none exists, DefaultConfigManager asks EnvironmentConfigProvider.TryPatch to apply matching child variables. If a lower-priority provider supplied an object, child variables patch that object and preserve existing members. If no provider produced a value, EnvironmentConfigProvider can construct an instantiable target type from child variables alone. That means APP__SETTINGS__DATABASE__PORT can update only Database.Port while preserving Database.Host from appsettings.json , or create App.Settings from child variables such as APP__SETTINGS__MODE=environment when no provider value exists. Indexed collection variables are supported for top-level values and object members: Plain text APP__SETTINGS__ENDPOINTS__0=https://one.example APP__SETTINGS__ENDPOINTS__1=https://two.example Override Pitfalls A direct object environment variable replaces the whole object; use child variables for partial overrides. Child patching targets public settable properties, initialized getter-only mutable collections or nested objects, and public writable fields. Types that cannot be instantiated need a lower-priority provider value or an already-initialized nested member to patch. Invalid child values are ignored instead of wiping out the lower-priority provider value. For example, a non-numeric APP__SETTINGS__DATABASE__PORT leaves the existing Port unchanged. Child environment variables patch provider-supplied values or construct an instantiable missing value; they do not patch Config\u003CT\u003E.DefaultValue . Put deploy-time defaults in a normal provider when they need member-level environment overrides. Validation Config\u003CT\u003E and ConfigStruct\u003CT\u003E validate the resolved value during initialization when the value is present. Validation runs after provider/default resolution, so defaults are held to the same rules as provider-supplied values. Optional ConfigStruct\u003CT\u003E values resolve through nullable T? provider lookups so a missing struct value is not confused with a configured zero-initialized value. AppSurface has two validation paths: object-valued config models use ordinary DataAnnotations on the model and its members scalar config wrappers use AppSurface scalar attributes or a ValidateValue override on the wrapper Use ordinary DataAnnotations on object-valued config models: C# using System . ComponentModel . DataAnnotations ; public sealed class RetryOptions { [ Range ( 1 , 5 ) ] public int Count { get ; init ; } } public sealed class RetryConfig : Config \u003C RetryOptions \u003E { } When validation fails, AppSurface throws one ConfigurationValidationException for the config key. The exception message is designed for logs: Plain text Configuration validation failed for key \u0027RetryConfig\u0027 (RetryConfig -\u003E RetryOptions): 1 error(s). - Count: The field Count must be between 1 and 5. The exception also exposes structured failures through Failures . Each failure includes the config key, wrapper type, value type, member names, and validation message. Attempted values are not exposed because config values often include secrets. Required Key Presence Config wrappers are optional by default. A missing provider value with no default leaves HasValue false and skips value validation. Use [ConfigKeyRequired] when the key itself must resolve a value during startup: C# using ForgeTrust . AppSurface . Config ; [ ConfigKeyRequired ] public sealed class ApiKeyConfig : Config \u003C string \u003E { } Required presence runs after provider/default resolution. A provider value satisfies the requirement, and a DefaultValue also satisfies it because the requirement is resolved presence, not provider-source auditing: C# [ ConfigKeyRequired ] public sealed class RegionConfig : Config \u003C string \u003E { public override string ? DefaultValue =\u003E \u0022 us-east-1 \u0022 ; } When a required wrapper has no provider value and no default, AppSurface throws ConfigurationValidationException through the same startup failure family used by object and scalar validation: Plain text Configuration validation failed for key \u0027ApiKeyConfig\u0027 (ApiKeyConfig -\u003E String): 1 error(s). - \u003Cvalue\u003E: A value is required for this configuration key. Combine presence and value validation when both contracts matter: C# [ ConfigKeyRequired ] [ ConfigValueNotEmpty ] public sealed class ApiKeyConfig : Config \u003C string \u003E { } In that example, a missing key reports the required-presence failure. A supplied empty string reports the ConfigValueNotEmpty value failure. The two attributes are intentionally separate so operators can distinguish \u0022nothing resolved\u0022 from \u0022a resolved value was invalid.\u0022 Scalar Value Validation Scalar wrappers such as Config\u003Cstring\u003E and ConfigStruct\u003Cint\u003E validate the resolved value from attributes placed on the wrapper class. This keeps simple configuration as a primitive while still giving startup-time validation: C# using ForgeTrust . AppSurface . Config ; [ ConfigValueRange ( 1 , 65535 ) ] public sealed class PortConfig : ConfigStruct \u003C int \u003E { } [ ConfigValueNotEmpty ] public sealed class ApiKeyConfig : Config \u003C string \u003E { } Built-in scalar attributes are intentionally small: Attribute Supported values Behavior ConfigValueNotEmptyAttribute string , Guid Rejects empty or whitespace-only strings and Guid.Empty . ConfigValueRangeAttribute(int minimum, int maximum) int , double Rejects values outside the inclusive range. Integer bounds are widened for double values, so [ConfigValueRange(1, 5)] works on ConfigStruct\u003Cdouble\u003E . ConfigValueRangeAttribute(double minimum, double maximum) int , double Rejects values outside the inclusive range using double comparisons. ConfigValueMinLengthAttribute(int length) string Rejects strings shorter than the configured length. An unsupported built-in attribute and value-type pairing fails as a structured ConfigurationValidationException . For example, [ConfigValueMinLength(3)] on ConfigStruct\u003Cint\u003E reports that the attribute supports String values instead of silently passing or throwing a cast exception. Use ValidateValue when the scalar rule is specific to your domain: C# using System . ComponentModel . DataAnnotations ; using ForgeTrust . AppSurface . Config ; public sealed class TenantSlugConfig : Config \u003C string \u003E { protected override IEnumerable \u003C ValidationResult \u003E ? ValidateValue ( string value , ValidationContext validationContext ) { if ( value . Contains ( \u0022 .. \u0022 , StringComparison . Ordinal ) ) { return [ new ValidationResult ( \u0022 Tenant slugs cannot contain \u0027..\u0027. \u0022 ) ] ; } return null ; } } Scalar validation runs only for non-null resolved scalar values. [ConfigValueNotEmpty] rejects an empty value that was supplied by a provider or default, but it does not make a missing config value required. Use [ConfigKeyRequired] when the key itself must exist. When both wrapper attributes and ValidateValue fail, attribute failures are reported first. Hook exceptions are not wrapped; they bubble to the caller so programming errors remain visible. Recursive Validation Top-level validation follows the normal DataAnnotations runtime behavior. Nested objects and collection items are validated only when explicitly marked with Microsoft Options validation attributes: C# using System . ComponentModel . DataAnnotations ; using Microsoft . Extensions . Options ; public sealed class DatabaseOptions { [ Required ] public string ? Host { get ; init ; } } public sealed class EndpointOptions { [ Required ] public string ? Url { get ; init ; } } public sealed class AppOptions { [ ValidateObjectMembers ] public DatabaseOptions ? Database { get ; init ; } [ ValidateEnumeratedItems ] public List \u003C EndpointOptions \u003E Endpoints { get ; init ; } = [ ] ; } public sealed class AppConfig : Config \u003C AppOptions \u003E { } Nested member paths are reported with dot and index notation, such as Database.Host and Endpoints[0].Url . Recursive validation tracks the active traversal path so cycles do not loop forever while repeated references are still reported at each distinct reachable path. Null nested objects and null collection items are skipped unless the containing property has [Required] . AppSurface uses the Microsoft marker attributes as the public authoring contract, but it owns the runtime traversal and ConfigurationValidationException output. It does not invoke the Options source generator or the IValidateOptions\u003CTOptions\u003E pipeline. Pitfalls DataAnnotations attributes such as [Range] on the wrapper class are not scalar validation attributes. Use AppSurface ConfigValue* attributes on scalar wrappers, or wrap related settings in an options object and use ordinary DataAnnotations on that object. [ConfigKeyRequired] on a wrapper and [Required] on an options property solve different problems. The wrapper attribute requires a config key to resolve; the DataAnnotations attribute validates a member on an object value that already resolved. Scalar validation validates values that exist after provider/default resolution. It is not a required-presence contract for missing keys. Required key presence does not report which provider did or did not supply a value. It only reports that provider/default resolution ended without a value. Built-in scalar attributes support only the value types documented above. Use ValidateValue for decimal, date/time, URI, domain-specific, or cross-cutting scalar rules. DataAnnotations can short-circuit. For example, object-level IValidatableObject validation may not run when property validation already failed. Recursive validation is opt-in. A nested object without [ValidateObjectMembers] and a collection without [ValidateEnumeratedItems] is not traversed. The Validator constructor overloads on Microsoft Options validation attributes are not supported by AppSurface Config validation. Example Run the scalar validation sample from the repository root: Bash dotnet run --project examples/config-validation It intentionally exits non-zero and prints the validation failure shape without echoing the invalid value. Notes The package is intended to make configuration access explicit and testable. Environment-aware providers make it easier to layer defaults, file configuration, and deployment-specific values.","snippet":"ForgeTrust.AppSurface.Config Strongly typed configuration primitives for AppSurface applications. Overview This package provides the configuration layer for AppSurface modules. It combines file-based configuration,...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Config"],"sourcePath":"Config/ForgeTrust.AppSurface.Config/README.md"},{"id":"console","path":"/docs/console","title":"Console Projects","summary":"This directory contains libraries and tools for building command-line applications.","headings":["Contents"],"bodyText":"Console Projects This directory contains libraries and tools for building command-line applications. Contents ForgeTrust.AppSurface.Console \u2013 CLI bootstrapping with CliFx. ForgeTrust.AppSurface.Console.Tests \u2013 Unit tests for console logic. \uD83C\uDFE0 Back to Root","snippet":"Console Projects This directory contains libraries and tools for building command-line applications. Contents ForgeTrust.AppSurface.Console \u2013 CLI bootstrapping with CliFx. ForgeTrust.AppSurface.Console.Tests \u2013 Unit...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","Console Projects"],"sourcePath":"Console/README.md"},{"id":"console/forgetrust.appsurface.console","path":"/docs/console/forgetrust.appsurface.console","title":"ForgeTrust.AppSurface.Console","summary":"Modular bootstrapping for .NET Console applications using [CliFx](https://github.com/Tyrrrz/CliFx).","headings":["Overview","Usage","Features","ConsoleOptions","Pitfalls"],"bodyText":"ForgeTrust.AppSurface.Console Modular bootstrapping for .NET Console applications using CliFx . Overview ForgeTrust.AppSurface.Console provides a structured way to build command-line tools. It automatically discovers and registers CliFx commands from modules, runs them inside the .NET Generic Host, and now exposes a startup options seam for console-specific behavior such as command-first output. Usage Create a startup class that inherits from ConsoleStartup\u003CTModule\u003E : C# public class MyConsoleStartup : ConsoleStartup \u003C MyRootModule \u003E { } In your Program.cs : C# await ConsoleApp \u003C MyRootModule \u003E . RunAsync ( args ) ; You can also customize console startup behavior at the entry point: C# using ForgeTrust . AppSurface . Core ; await ConsoleApp \u003C MyRootModule \u003E . RunAsync ( args , options =\u003E { options . OutputMode = ConsoleOutputMode . CommandFirst ; } ) ; If you are using a custom startup type directly, the same configuration can be applied fluently: C# await new MyConsoleStartup ( ) . WithOptions ( options =\u003E options . OutputMode = ConsoleOutputMode . CommandFirst ) . RunAsync ( args ) ; Features Command Discovery : Automatically registers classes implementing ICommand from the entry point assembly and dependent modules. Hosted Runner : Integrates with the .NET Generic Host to manage service lifecycles during command execution. Console Options : ConsoleOptions lets entry points configure shared console behavior before the host is built. ConsoleOptions ConsoleOptions is the public startup configuration surface for AppSurface console apps. OutputMode defaults to ConsoleOutputMode.Default . ConsoleOutputMode.Default preserves the standard Generic Host experience, including lifecycle output that may appear alongside command output. ConsoleOutputMode.CommandFirst suppresses ambient host and command-runner lifecycle information so help, validation, and command-owned progress remain the primary console experience. CustomRegistrations runs after AppSurface\u0027s built-in console registrations so advanced hosts and tests can override services such as CliFx.Infrastructure.IConsole or add extra logging providers. Use CommandFirst for public CLIs where first-touch output is part of the product surface. Leave the default in place for internal tools or apps where host lifecycle logs are useful operational context. Pitfalls CommandFirst suppresses ambient lifecycle information, not command-owned progress. Your command still needs to log or write the progress messages users should see. Console options are applied before host creation. Configure them at the entry point or through WithOptions(...) , not inside command handlers. CustomRegistrations overrides services late in the startup pipeline. Use it intentionally for host-level customization, not as a replacement for normal module service registration. If you override console startup behavior in a derived startup class, keep the shared options path intact so entry-point configuration still reaches the host. \uD83D\uDCC2 Back to Console List | \uD83C\uDFE0 Back to Root","snippet":"ForgeTrust.AppSurface.Console Modular bootstrapping for .NET Console applications using CliFx . Overview ForgeTrust.AppSurface.Console provides a structured way to build command-line tools. It automatically discovers...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Console"],"sourcePath":"Console/ForgeTrust.AppSurface.Console/README.md"},{"id":"contributing","path":"/docs/contributing","title":"Contributing to AppSurface","summary":"AppSurface is putting its release contract in place before the first tagged version. This file explains the contribution rules that feed the public release surface.","headings":["Feedback path","Local setup","Working on docs","Release contract","Writing release notes","Maintainer workflow","Local verification"],"bodyText":"Contributing to AppSurface AppSurface is putting its release contract in place before the first tagged version. This file explains the contribution rules that feed the public release surface. Feedback path AppSurface treats docs and onboarding feedback as product input, not as a second-class support queue. File issues when a package, example, README, or release note leaves you unable to reproduce the intended path. For quick access, use GitHub\u0027s issue template chooser: choose an issue template . Use the Bug report issue form when behavior is broken or surprising. Use the Feature request issue form when you can name a focused product capability, API shape, workflow, or example that would remove friction. Use the Docs or developer experience feedback issue form when the code may work, but the route to understanding it is unclear. Do not use public issue forms for suspected vulnerabilities, leaked secrets, or exploit details. Use the security policy and report sensitive findings privately. Include the command, page, example, package, or API where the confusion started. The sharpest reports name the exact step that failed and the next thing you expected to see. If you are unsure whether something is a bug, feature request, or docs gap, file the docs/DX form and explain the behavior you expected. Avoid broad requests such as \u0022improve the docs\u0022 without a concrete page, task, or decision point. Narrow feedback is easier to verify and much more likely to turn into a useful change. Local setup Use a current .NET SDK supported by this repository, then restore and build from the repository root before opening a pull request: Bash dotnet restore dotnet build Run the sample or package-specific command you changed, and include that command in your pull request notes. For broad changes, also run the full test suite and coverage command listed in Local verification . Working on docs Documentation changes should explain both how to use an API and why a reader would choose it. When a docs change touches public behavior, update the package-level README, repository-level entry point, or release note surface that helps someone discover the change. Good docs pull requests usually include: Reference content for API shape, defaults, constraints, and examples. Decision guidance that explains when to use the API and when another approach fits better. Pitfalls that call out ordering requirements, generated output, hosting assumptions, or common mistakes. Verification notes for commands, links, snippets, or examples that were checked. Release contract AppSurface releases the monorepo in unison. Packages, CLI tooling, examples, and docs-facing behavior all roll into the same next version. Pull request titles that land on main must follow Conventional Commits using release-note-friendly types such as feat , fix , docs , perf , refactor , test , build , ci , chore , or revert . The squash-merge title is the durable signal for future automation and changelog grouping. Update releases/unreleased.md whenever a pull request changes behavior, usage guidance, release policy, examples, or docs consumers would care about in release notes. Maintainers may apply the no-unreleased-entry label only for changes that do not belong in the public release story, such as repo administration or workflow-only cleanup. Writing release notes Start from the public release hub . Keep CHANGELOG.md compact. It is the ledger, not the full story. Put detailed adoption notes in the current unreleased page or a tagged release page under releases/ . Capture breaking or behavior-changing updates in the unreleased page even before v0.1.0 . Finalized migration guidance moves into the tagged release page when the version ships. Maintainer workflow Use the release authoring checklist when preparing a release. Use the tagged release template when cutting the first versioned release note. Keep private maintainer-only recovery notes outside harvested public docs. In this repository, .github/ is the safe home for that material. Local verification Build and test the full solution before pushing substantive changes: Bash dotnet build dotnet test --no-build ./scripts/coverage-solution.sh","snippet":"Contributing to AppSurface AppSurface is putting its release contract in place before the first tagged version. This file explains the contribution rules that feed the public release surface. Feedback path AppSurface...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","Contributing to AppSurface"],"sourcePath":"CONTRIBUTING.md"},{"id":"dependency","path":"/docs/dependency","title":"Dependency Injection Projects","summary":"Integrations with various dependency injection containers and advanced DI utilities.","headings":["Contents"],"bodyText":"Dependency Injection Projects Integrations with various dependency injection containers and advanced DI utilities. Contents ForgeTrust.AppSurface.Dependency.Autofac \u2013 Autofac container integration. \uD83C\uDFE0 Back to Root","snippet":"Dependency Injection Projects Integrations with various dependency injection containers and advanced DI utilities. Contents ForgeTrust.AppSurface.Dependency.Autofac \u2013 Autofac container integration. \uD83C\uDFE0 Back to Root","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","Dependency Injection Projects"],"sourcePath":"Dependency/README.md"},{"id":"dependency/forgetrust.appsurface.dependency.autofac","path":"/docs/dependency/forgetrust.appsurface.dependency.autofac","title":"ForgeTrust.AppSurface.Dependency.Autofac","summary":"Autofac IoC container integration for AppSurface modules.","headings":["Overview","Usage"],"bodyText":"ForgeTrust.AppSurface.Dependency.Autofac Autofac IoC container integration for AppSurface modules. Overview This package allows modules to participate in Autofac service registration, enabling advanced DI features not available in the default .NET service collection. Usage Inherit from AppSurfaceAutofacModule instead of IAppSurfaceModule if you need to use Autofac-specific registrations. C# public class MyAutofacModule : AppSurfaceAutofacModule { protected override void Load ( ContainerBuilder builder ) { // Custom Autofac registrations } } \uD83D\uDCC2 Back to Dependency List | \uD83C\uDFE0 Back to Root","snippet":"ForgeTrust.AppSurface.Dependency.Autofac Autofac IoC container integration for AppSurface modules. Overview This package allows modules to participate in Autofac service registration, enabling advanced DI features not...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Dependency.Autofac"],"sourcePath":"Dependency/ForgeTrust.AppSurface.Dependency.Autofac/README.md"},{"id":"examples","path":"/docs/examples","title":"Examples","summary":"This directory contains sample applications that use **ForgeTrust.AppSurface**.","headings":[],"bodyText":"Examples This directory contains sample applications that use ForgeTrust.AppSurface . Console app example \u2013 shows how to build a simple console application using CliFx for command definitions. Web app example \u2013 demonstrates starting a minimal ASP.NET Core web application. Config validation example \u2013 shows scalar validation on a strongly typed config wrapper and the startup failure shape. \uD83C\uDFE0 Back to Root","snippet":"Examples This directory contains sample applications that use ForgeTrust.AppSurface . Console app example \u2013 shows how to build a simple console application using CliFx for command definitions. Web app example \u2013...","pageType":"example","pageTypeLabel":"Example","pageTypeVariant":"example","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Examples","publicSection":"examples","publicSectionLabel":"Examples","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Examples"],"sourcePath":"examples/README.md"},{"id":"examples/config-validation","path":"/docs/examples/config-validation","title":"Config validation example","summary":"This sample shows scalar validation on a strongly typed AppSurface config wrapper.","headings":[],"bodyText":"Config validation example This sample shows scalar validation on a strongly typed AppSurface config wrapper. Run it from the repository root: Bash dotnet run --project examples/config-validation The sample intentionally exits with a non-zero status so you can see the startup failure shape: Plain text Configuration validation failed for key \u0027PortConfig\u0027 (PortConfig -\u003E Int32): 1 error(s). - \u003Cvalue\u003E: The configuration value must be between 1 and 65535. Fix the configured value or relax the scalar rule on the config wrapper. The failed value is not printed. Configuration values often include secrets, so validation output names the key and rule without echoing the attempted value.","snippet":"Config validation example This sample shows scalar validation on a strongly typed AppSurface config wrapper. Run it from the repository root: Bash dotnet run --project examples/config-validation The sample...","pageType":"example","pageTypeLabel":"Example","pageTypeVariant":"example","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Examples","publicSection":"examples","publicSectionLabel":"Examples","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Examples","Config validation example"],"sourcePath":"examples/config-validation/README.md"},{"id":"examples/console-app","path":"/docs/examples/console-app","title":"Console app example","summary":"This sample demonstrates how to build a console application with **ForgeTrust.AppSurface**.","headings":[],"bodyText":"Console app example This sample demonstrates how to build a console application with ForgeTrust.AppSurface . It defines a module and a greet command. The command uses attributes from the CliFx library\u2014see the CliFx documentation on attributes for more details. Run the sample with: Bash dotnet run --project examples/console-app/ConsoleAppExample.csproj -- greet World This will output: Plain text Hello, World!","snippet":"Console app example This sample demonstrates how to build a console application with ForgeTrust.AppSurface . It defines a module and a greet command. The command uses attributes from the CliFx library\u2014see the CliFx...","pageType":"example","pageTypeLabel":"Example","pageTypeVariant":"example","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Examples","publicSection":"examples","publicSectionLabel":"Examples","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Examples","Console app example"],"sourcePath":"examples/console-app/README.md"},{"id":"examples/razorwire-mvc","path":"/docs/examples/razorwire-mvc","title":"RazorWire MVC Example","summary":"This sample is the concrete proof behind the RazorWire package README. It shows how returned Razor fragments, islands, and SSE fit into a normal ASP.NET Core MVC app without a separate client rendering stack.","headings":["Start Here: Return Razor Fragments","What Just Happened","Files Behind the Hero Flow","Proof Slice","If Your Result Differs","Broader Sample Features","Islands","Live Updates over SSE","Registration and Message Publishing","Failed Form UX","Project Structure","Development Notes"],"bodyText":"RazorWire MVC Example This sample is the concrete proof behind the RazorWire package README. It shows how returned Razor fragments, islands, and SSE fit into a normal ASP.NET Core MVC app without a separate client rendering stack. Start Here: Return Razor Fragments Run the application from the repository root: Bash dotnet run --project examples/razorwire-mvc/RazorWireWebExample.csproj This is the repo-local path while the public v0.1 package install flow is being finalized. It assumes you are in a clone of this repository with the .NET 10 SDK installed. If you cd examples/razorwire-mvc first, dotnet run also works from there. Open the URL printed in the console and navigate to /Reactivity . Wait for the Permanent Island sidebar to load. Click the \u002B button in the counter widget. Watch Instance Score and Session Score update in place without a full page reload. That is the core RazorWire workflow in one interaction: a normal MVC form posts, the controller returns targeted Razor fragments, and the UI updates only where it needs to. To inspect failed-submission conventions, navigate to /Reactivity/FormFailures . That page intentionally triggers validation, anti-forgery, authorization, malformed request, and server failures so you can compare server-handled errors with the default runtime fallback. What Just Happened Plain text /Reactivity -\u003E loads the Permanent Island from /Reactivity/Sidebar -\u003E renders the Counter view component inside that island -\u003E posts the counter form to ReactivityController.IncrementCounter -\u003E returns a RazorWire stream with targeted updates -\u003E updates the two counters and replaces the hidden input for the next click Files Behind the Hero Flow examples/razorwire-mvc/Views/Reactivity/Index.cshtml loads the permanent island with src=\u0022/Reactivity/Sidebar\u0022 . examples/razorwire-mvc/Views/Shared/_Sidebar.cshtml hosts the island content and invokes the Counter view component. examples/razorwire-mvc/Views/Shared/Components/Counter/Default.cshtml renders the counter values plus the IncrementCounter form. examples/razorwire-mvc/Controllers/ReactivityController.cs returns the targeted stream updates. examples/razorwire-mvc/Views/Reactivity/_CounterInput.cshtml replaces the hidden clientCount input after each click. Proof Slice examples/razorwire-mvc/Views/Shared/Components/Counter/Default.cshtml Razor \u003C div id = \u0022 instance-score-value \u0022 class = \u0022 text-2xl font-black text-indigo-600 tabular-nums \u0022 \u003E @ Model \u003C/ div \u003E \u003C div id = \u0022 session-score-value \u0022 class = \u0022 text-2xl font-black text-indigo-400 tabular-nums \u0022 \u003E 0 \u003C/ div \u003E \u003C form asp-controller = \u0022 Reactivity \u0022 asp-action = \u0022 IncrementCounter \u0022 method = \u0022 post \u0022 rw-active = \u0022 true \u0022 data-counter-form \u003E \u003C input type = \u0022 hidden \u0022 name = \u0022 clientCount \u0022 id = \u0022 client-count-input \u0022 value = \u0022 0 \u0022 /\u003E \u003C button type = \u0022 submit \u0022 aria-label = \u0022 Increment counter \u0022 \u003E \u002B \u003C/ button \u003E \u003C/ form \u003E examples/razorwire-mvc/Controllers/ReactivityController.cs C# [ HttpPost ] [ ValidateAntiForgeryToken ] public IActionResult IncrementCounter ( [ FromForm ] int clientCount ) { CounterViewComponent . Increment ( ) ; clientCount \u002B\u002B ; if ( Request . IsTurboRequest ( ) ) { return this . RazorWireStream ( ) . Update ( \u0022 instance-score-value \u0022 , CounterViewComponent . Count . ToString ( ) ) . Update ( \u0022 session-score-value \u0022 , clientCount . ToString ( ) ) . ReplacePartial ( \u0022 client-count-input \u0022 , \u0022 _CounterInput \u0022 , clientCount ) . BuildResult ( ) ; } var referer = Request . Headers [ \u0022 Referer \u0022 ] . ToString ( ) ; return Url . IsLocalUrl ( referer ) ? Redirect ( referer ) : RedirectToAction ( nameof ( Index ) ) ; } examples/razorwire-mvc/Views/Reactivity/_CounterInput.cshtml Razor \u003C input type = \u0027 hidden \u0027 name = \u0027 clientCount \u0027 id = \u0027 client-count-input \u0027 value = \u0027 @ Model \u0027 /\u003E If Your Result Differs If the page loads on a different port, use the URL printed by dotnet run . If clicking \u002B gives you a bare 400 Bad Request , check the package docs for Security \u0026 Anti-Forgery . That is the first thing to verify when you copy this pattern into another page or app. If the form does not update in place, check the same anti-forgery guidance first, then confirm you are still posting with rw-active=\u0022true\u0022 and returning a RazorWire stream from IncrementCounter . If you want the broader sample context instead of the focused proof, continue below. Broader Sample Features Islands The sample uses rw:island to load and persist independent UI regions. ReactivityController.Sidebar() returns the permanent sidebar island. ReactivityController.UserList() returns the UserList view component inside its own island. Views/Home/Index.cshtml , Views/Reactivity/Index.cshtml , and Views/Navigation/Index.cshtml all reuse the same permanent-island so it can persist across page transitions. Live Updates over SSE The sample also demonstrates live multi-client updates. Views/Reactivity/Index.cshtml includes \u003Crw:stream-source id=\u0022rw-stream-reactivity\u0022 channel=\u0022reactivity\u0022 permanent=\u0022true\u0022 /\u003E . ReactivityController.PublishMessage() pushes new messages to every connected client. ReactivityController.BroadcastUserPresenceAsync() updates the user list and online count across sessions. Registration and Message Publishing The reactivity page includes two additional form flows: Views/Reactivity/_UserRegistration.cshtml posts to RegisterUser and swaps the register and message forms. Views/Reactivity/_MessageForm.cshtml posts to PublishMessage and prepends messages into the live feed. RegisterUser stores the display name in a razorwire-username cookie with Secure , HttpOnly , and SameSite=Lax set. Keep that shape when copying the sample into an application: the cookie is only a convenience for the demo identity, but browsers can otherwise send it over cleartext HTTP. Outside localhost-style development, serve the flow over HTTPS before depending on the cookie. During local development, use the printed localhost URL rather than swapping in 127.0.0.1 ; browsers treat those as different cookie hosts, and some will reject Secure cookies from an HTTP loopback IP. Those flows are richer than the counter demo, but the counter is the cleanest first proof because it does not depend on stream-hub context to feel convincing. Failed Form UX The sample includes a dedicated /Reactivity/FormFailures page that demonstrates: FormValidationErrors returning a 422 validation stream with X-RazorWire-Form-Handled: true . Development anti-forgery diagnostics for a raw form that intentionally omits __RequestVerificationToken . Default runtime fallbacks for unhandled 400 , 403 , and 500 responses. Consumer customization with CSS variables and razorwire:form:failure in manual mode. See the package guide for the API contract and troubleshooting notes: Failed Form UX . Project Structure Controllers/ReactivityController.cs : main demo controller for islands, form posts, and stream responses. Views/Reactivity/ : reactivity page plus registration, message, and counter partials. Views/Shared/ : shared island and view component rendering. ViewComponents/ : view component entry points such as Counter and UserList . Services/ : in-memory sample services such as UserPresenceService and MessageStore . Development Notes To enable Razor Runtime Compilation and live static asset updates in the sample, run in the Development environment, for example with ASPNETCORE_ENVIRONMENT=Development . Local assets such as site.js and site.css automatically receive version hashes for cache busting. You can still use asp-append-version=\u0022true\u0022 explicitly if you want to make that behavior obvious in markup.","snippet":"RazorWire MVC Example This sample is the concrete proof behind the RazorWire package README. It shows how returned Razor fragments, islands, and SSE fit into a normal ASP.NET Core MVC app without a separate client...","pageType":"example","pageTypeLabel":"Example","pageTypeVariant":"example","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Examples","publicSection":"examples","publicSectionLabel":"Examples","isSectionLanding":false,"order":20,"sequenceKey":"razorwire-proof","canonicalSlug":null,"relatedPages":["Web/ForgeTrust.RazorWire/README.md","Web/ForgeTrust.RazorWire/Docs/form-failures.md","Web/ForgeTrust.RazorWire/Docs/antiforgery.md"],"breadcrumbs":["Examples","RazorWire MVC Example"],"sourcePath":"examples/razorwire-mvc/README.md"},{"id":"examples/web-app","path":"/docs/examples/web-app","title":"Web app example","summary":"This example shows how to build a minimal ASP.NET Core application using **ForgeTrust.AppSurface.Web**.","headings":[],"bodyText":"Web app example This example shows how to build a minimal ASP.NET Core application using ForgeTrust.AppSurface.Web . Run the application: Bash dotnet run --project examples/web-app -- --port 5055 Then open http://127.0.0.1:5055 or run: Bash curl http://127.0.0.1:5055 Expected output: Plain text Hello World from the root! The explicit --port keeps the quickstart copy-paste stable. Without it, AppSurface may choose a deterministic development port for your current worktree; use the startup log as the source of truth.","snippet":"Web app example This example shows how to build a minimal ASP.NET Core application using ForgeTrust.AppSurface.Web . Run the application: Bash dotnet run --project examples/web-app -- --port 5055 Then open...","pageType":"example","pageTypeLabel":"Example","pageTypeVariant":"example","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Examples","publicSection":"examples","publicSectionLabel":"Examples","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Examples","Web app example"],"sourcePath":"examples/web-app/README.md"},{"id":"forgetrust.appsurface.core","path":"/docs/forgetrust.appsurface.core","title":"ForgeTrust.AppSurface.Core","summary":"The foundation of the AppSurface ecosystem. This package defines the core abstractions, the startup pipeline, and the module system that powers all other AppSurface libraries.","headings":["Overview","Key Concepts","Application labels and host identity","Startup dependency graph","Logging in Static Utilities","Usage"],"bodyText":"ForgeTrust.AppSurface.Core The foundation of the AppSurface ecosystem. This package defines the core abstractions, the startup pipeline, and the module system that powers all other AppSurface libraries. Overview The Core library is designed to be lightweight and implementation-agnostic. It provides the infrastructure to: Define Modules ( IAppSurfaceModule , IAppSurfaceHostModule ) that encapsulate logic. Manage Dependency Graphs between modules. Provide a consistent Startup Pipeline ( AppSurfaceStartup ) that sits on top of the .NET Generic Host. Key Concepts IAppSurfaceModule : The base interface for any unit of functionality that needs to register services or configure the application. StartupContext : Provides metadata about the running application, including the user-facing application label, assembly-backed host identity, application discovery assembly, environment, and startup-level console output mode. ConsoleOutputMode : Shared core enum that lets console-oriented packages describe whether command output should remain host-centric or command-first. AppSurfaceStartup : The base class that orchestrates the host building and service registration process. AppSurfaceStartup.RegisterDependencies : A protected seam for specialized startup types that need the module graph prepared before they build the Generic Host. Application labels and host identity StartupContext.ApplicationName is a display label. Use it for generated documentation titles, command output, OpenAPI branding, and other user-facing product surfaces. StartupContext.HostApplicationName is the assembly-backed identity assigned to IHostEnvironment.ApplicationName and the Generic Host applicationName setting. It defaults to the process entry assembly when one is available so cross-assembly hosts still resolve the correct static web asset manifest. When StartupContext.OverrideEntryPointAssembly is set, it uses that override assembly name instead. If no entry assembly is available, AppSurface falls back to the root module assembly as a defensive last resort. StartupContext.EntryPointAssembly is the assembly AppSurface scans for application-owned commands, MVC application parts, Aspire components, and similar extensibility points. It defaults to the root module assembly so test runners and shared outer hosts do not accidentally scan the xUnit/VSTest process entry assembly. When StartupContext.OverrideEntryPointAssembly is set, that override applies to both discovery and host manifest identity. Keep these values separate. ASP.NET static web assets use the host application name to find runtime manifests. Passing a custom display label such as CustomDocsHost into the host environment can make static asset requests resolve against a manifest that does not exist. When a test or custom host needs a different manifest identity, set StartupContext.OverrideEntryPointAssembly instead of overloading ApplicationName . Startup dependency graph AppSurfaceStartup registers framework dependencies and root-module dependencies exactly once per StartupContext . Standard hosts do not need to call anything directly: the registration happens during host-builder creation before module hooks and service registration run. Specialized startup types can call the protected RegisterDependencies(StartupContext context) seam earlier when they need module-derived options before IHostBuilder.Build() . AppSurface Web uses this to resolve WebOptions.StartupTimeout before arming its startup watchdog around host creation and startup. Call RegisterDependencies before reading StartupContext.GetDependencies() for startup-shaping decisions. Repeated calls with the same context are no-ops, but module registration is still part of startup composition, so avoid calling it from request-time code or from parallel threads. Logging in Static Utilities Core static utilities stay host-agnostic: they do not reach into a global logger, service provider, or ambient startup state. When a public static helper has useful diagnostics, expose an additive overload with an explicit non-null ILogger parameter and keep the existing no-logger overload silent. Private shared implementations may accept ILogger? only to avoid duplicating logic between the silent and diagnostic paths. Use this pattern when a helper performs fallback behavior that callers may want to audit. For example, PathUtils.FindRepositoryRoot(startPath, logger) logs a warning when startPath does not exist and repository-root discovery has to continue from the nearest existing ancestor. Prefer ordinary dependency injection for services, modules, hosted services, and application-owned classes. The optional logger pattern is only for static helpers where injecting a service instance would make the API harder to use or force unrelated callers to construct infrastructure. Define static helper log messages with the source-generated [LoggerMessage] attribute on private static partial methods. Give each message a stable event ID, level, and template. Do not use ad hoc logger.Log... calls for new Core diagnostics when the message is part of an intentional API behavior. Pitfalls: Do not create a static LoggerFactory inside a utility. That couples Core to a console/logging policy the host did not choose. Do not throw only because a fallback warning was logged. Keep the documented return behavior unless the input contract itself is invalid. Do not swallow cleanup failures silently when a logger is available. Log them at Debug when they are intentionally suppressed to preserve the primary exception or cancellation path. Usage Most users will use a more specialized package like ForgeTrust.AppSurface.Web or ForgeTrust.AppSurface.Console , which inherit from the abstractions provided here. \uD83C\uDFE0 Back to Root","snippet":"ForgeTrust.AppSurface.Core The foundation of the AppSurface ecosystem. This package defines the core abstractions, the startup pipeline, and the module system that powers all other AppSurface libraries. Overview The...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Core"],"sourcePath":"ForgeTrust.AppSurface.Core/README.md"},{"id":"guides/from-program-cs-to-module","path":"/docs/guides/from-program-cs-to-module","title":"From Program.cs to an AppSurface Module","summary":"See browser status pages and production error pages move from local startup policy to a named AppSurface Web behavior contract.","headings":["Plain ASP.NET Core Baseline","AppSurface Module Version","Behavior Contract","What The Module Buys","Pitfalls"],"bodyText":"From Program.cs to an AppSurface Module The clearest AppSurface proof is not a smaller Program.cs . It is a startup policy that becomes named, tested, and reusable. This page uses browser status pages and production error pages from ForgeTrust.AppSurface.Web as that proof. Plain ASP.NET Core Baseline ASP.NET Core can handle this directly. A small app can use built-in status-code pages, exception handling, Problem Details, endpoint handlers, or custom middleware. That baseline is correct when the policy is local and obvious. The cost appears when several services must remember the same details: Which requests should get browser HTML instead of API-friendly behavior? Which status codes have conventional pages? Which route previews are safe for checking the pages? Which production 500 page avoids leaking exception details? Where does each service document the convention? Plain ASP.NET Core gives you the primitives. AppSurface gives the team one named place to express the convention. AppSurface Module Version AppSurface Web exposes the concern through WebOptions.Errors . C# public void ConfigureWebOptions ( StartupContext context , WebOptions options ) { options . Mvc = options . Mvc with { MvcSupportLevel = MvcSupport . Controllers } ; options . Errors . UseConventionalBrowserStatusPages ( ) ; options . Errors . UseConventionalExceptionPage ( ) ; } The browser status page call enables conventional browser-facing pages for empty 401 , 403 , and 404 responses. The production exception page call enables a generic browser-facing 500 page for unhandled exceptions. These are separate features. Status-code pages do not catch thrown exceptions. Behavior Contract AppSurface Web verifies this behavior in package tests: Bash dotnet test Web/ForgeTrust.AppSurface.Web.Tests/ForgeTrust.AppSurface.Web.Tests.csproj --filter \u0022 BrowserStatusPageTests|ConventionalExceptionPageTests \u0022 The source-of-truth test classes are: Web/ForgeTrust.AppSurface.Web.Tests/BrowserStatusPageTests.cs Web/ForgeTrust.AppSurface.Web.Tests/ConventionalExceptionPageTests.cs Those tests cover the HTTP contract this page relies on: Browser requests to empty supported status responses render recovery-oriented HTML and preserve the original status. Direct preview routes such as /_appsurface/errors/404 render the conventional page. JSON and non-HTML requests do not receive browser HTML. Production exception pages return a generic 500 page for browser requests. The generic 500 page includes a request id but not exception messages, stack traces, headers, cookies, route values, or form fields. JSON requests to throwing endpoints do not render the conventional HTML exception page. What The Module Buys The value is not that ASP.NET Core cannot do this. It can. The value is that a team can point service owners at one module-level behavior contract instead of copying a Program.cs block and hoping every service keeps the same edge cases. For a single service, this is useful when the error posture is important enough to name. Across several services, it becomes a standard. Pitfalls Do not enable browser pages for API-only behavior that should stay JSON or Problem Details. Do not expose exception details on production 500 pages. Do not assume status-code pages catch thrown exceptions. They handle empty status responses; exception handling is a separate pipeline. Do not duplicate the full Web package reference here. Use the AppSurface Web README for the full API shape. Next recovery path: Troubleshoot Startup and Modules","snippet":"From Program.cs to an AppSurface Module The clearest AppSurface proof is not a smaller Program.cs . It is a startup policy that becomes named, tested, and reusable. This page uses browser status pages and production...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":["Program.cs","error pages","status pages","module extraction"],"keywords":["UseConventionalBrowserStatusPages","UseConventionalExceptionPage","WebOptions.Errors","BrowserStatusPageMode"],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":40,"sequenceKey":"appsurface-evaluator","canonicalSlug":null,"relatedPages":["Web/ForgeTrust.AppSurface.Web/README.md","ForgeTrust.AppSurface.Core/README.md","start-here/should-i-use-appsurface.md"],"breadcrumbs":["How-to Guides","From Program.cs to an AppSurface Module"],"sourcePath":"guides/from-program-cs-to-module.md"},{"id":"LICENSE.html","path":"/docs/LICENSE.html","title":"LICENSE","summary":"\u003Chttps://polyformproject.org/licenses/small-business/1.0.0\u003E","headings":["Acceptance","Copyright License","Distribution License","Notices","Changes and New Works License","Patent License","Fair Use","Small Business","No Other Rights","Patent Defense","Violations","No Liability","Definitions"],"bodyText":"PolyForm Small Business License 1.0.0 https://polyformproject.org/licenses/small-business/1.0.0 Acceptance In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses. Copyright License The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor\u0027s copyright in it for any permitted purpose. However, you may only distribute the software according to Distribution License and make changes or new works based on the software according to Changes and New Works License . Distribution License The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by Changes and New Works License . Notices You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with Required Notice: that the licensor provided with the software. For example: Required Notice: Copyright Yoyodyne, Inc. ( http://example.com ) Changes and New Works License The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose. Patent License The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software. Fair Use You may have \u0022fair use\u0022 rights for the software under the law. These terms do not limit them. Small Business Use of the software for the benefit of your company is use for a permitted purpose if your company has fewer than 100 total individuals working as employees and independent contractors, and less than 1,000,000 USD (2019) total revenue in the prior tax year. Adjust this revenue threshold for inflation according to the United States Bureau of Labor Statistics\u0027 consumer price index for all urban consumers, U.S. city average, for all items, not seasonally adjusted, with 1982\u20131984=100 reference base. No Other Rights These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses. Patent Defense If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company. Violations The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately. No Liability As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim. Definitions The licensor is the individual or entity offering these terms, and the software is the software the licensor makes available under these terms. You refers to the individual or entity agreeing to these terms. Your company is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect. Your licenses are all the licenses granted to you for the software under these terms. Use means anything you do with the software requiring one of your licenses.","snippet":"PolyForm Small Business License 1.0.0 https://polyformproject.org/licenses/small-business/1.0.0 Acceptance In order to get any license under these terms, you must agree to them as both strict obligations and...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","LICENSE"],"sourcePath":"LICENSE"},{"id":"licensing","path":"/docs/licensing","title":"AppSurface licensing","summary":"Explains the OSS license boundary, commercial purchase intent, and package-readiness signals.","headings":["What the OSS license covers","What commercial purchase covers","Package readiness","Sharp edges"],"bodyText":"AppSurface licensing AppSurface and RazorWire are intended for public OSS adoption and commercial purchase/support. The current OSS grant is the Polyform Small Business License 1.0.0; the canonical license text lives in the repository LICENSE file. Until the first tagged package release, treat the repository license as the source-of-truth grant for source use and treat commercial terms as a separate agreement from ForgeTrust. What the OSS license covers Reading, evaluating, building, and contributing to the repository. Using published OSS package versions under the repository license terms. Sharing examples, issues, pull requests, and integration feedback in public. What commercial purchase covers Commercial support expectations that are not promised by the OSS license alone. Private adoption help, migration planning, and packaging guidance. Future commercial features or services that ForgeTrust may offer around AppSurface and RazorWire. Package readiness The direct-install packages marked commercial_ready in packages/package-index.yml are the public package surface we intend to support first. Support runtime, proof-host, and excluded package rows are visible for transparency, but they are not positioned as standalone commercial products. Sharp edges Pre-1.0 package versions may still make breaking changes. Read releases/upgrade-policy.md , releases/unreleased.md , and CHANGELOG.md before adopting a new version in production.","snippet":"AppSurface licensing AppSurface and RazorWire are intended for public OSS adoption and commercial purchase/support. The current OSS grant is the Polyform Small Business License 1.0.0; the canonical license text lives...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":"adopters","component":null,"aliases":[],"keywords":["maintainers","commercial buyers","Polyform Small Business License","commercial purchase"],"status":"draft","navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":["packages/package-index.yml","packages/README.md","releases/upgrade-policy.md"],"breadcrumbs":["How-to Guides","AppSurface licensing"],"sourcePath":"licensing.md"},{"id":"Namespaces.html","path":"/docs/Namespaces.html","title":"Namespaces","summary":"Namespaces ForgeTrust Global","headings":[],"bodyText":"Namespaces ForgeTrust Global","snippet":"Namespaces ForgeTrust Global","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces"],"sourcePath":"Namespaces"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html","title":"Aspire","summary":"Type AspireStartupContext Provides context and helper methods during the Aspire application startup process. Method Resolve IResourceBuilder\u003CTResource\u003E Resolve \u003CTResource\u003E ( IAspireComponent\u003CTResource\u003E dependency )...","headings":["AspireStartupContext","Resolve","GetPathFromRoot","IAspireComponent\u003CT\u003E","Generate","IAspireComponent","AspireProfile","GetDependencies","GetComponents","PassThroughArgs","AspireApp","RunAsync","AspireApp\u003CTModule\u003E","AspireAppStartup\u003CTModule\u003E","ConfigureAdditionalServices"],"bodyText":"Type AspireStartupContext Provides context and helper methods during the Aspire application startup process. Method Resolve IResourceBuilder\u003CTResource\u003E Resolve \u003CTResource\u003E ( IAspireComponent\u003CTResource\u003E dependency ) Resolves an Aspire resource from a component, ensuring each component is only generated once. Type Parameters TResource The type of the resource. Parameters dependency The component providing the resource. Returns A resource builder for the resolved resource. Method GetPathFromRoot string GetPathFromRoot ( string relativePath ) Computes an absolute path from a path relative to the application root. Parameters relativePath The relative path. Returns The computed absolute path. Type IAspireComponent\u003CT\u003E Indicates that the implementing class is an Aspire component that can generate resources for the application. Classes implementing this interface are responsible for generating resources of type T , Type Parameters T The type of resource the component generates. Method Generate IResourceBuilder\u003CT\u003E Generate ( AspireStartupContext context , IDistributedApplicationBuilder appBuilder ) Generates and adds a resource to the Aspire distributed application builder. Parameters context The Aspire startup context. appBuilder The distributed application builder. Returns A resource builder for the generated resource. Type IAspireComponent The base interface for Aspire components. For now this interface does not define any members, but it serves as a marker interface to identify classes that are Aspire components. This allows for future expansion and additional functionality to be added to all Aspire components if needed. Type AspireProfile A base class for defining an Aspire profile as a CLI command. Method GetDependencies IEnumerable\u003CAspireProfile\u003E GetDependencies () Gets the dependencies (other profiles) that this profile requires. Returns An enumerable of dependent profiles. Method GetComponents IEnumerable\u003CIAspireComponent\u003E GetComponents () Gets the Aspire components that compose this profile. Returns An enumerable of Aspire components. Property PassThroughArgs string[] PassThroughArgs { get; } Gets the command-line arguments to pass through to the Aspire host. Type AspireApp Entry point for running an Aspire application with no specific root module. Remarks Use AspireApp.RunAsync(string[]) when the AppHost should use the framework-default NoHostModule and discover Aspire components from the calling assembly. If the caller has a concrete root module type that should participate in compile-time dependency and configuration registration, prefer AspireApp{TModule}.RunAsync(string[]) instead. Method RunAsync Task RunAsync ( string[] args ) Runs the Aspire application asynchronously. Parameters args Command-line arguments. Returns A task representing the run operation. Type AspireApp\u003CTModule\u003E Entry point for running an Aspire application with a specific root module. Type Parameters TModule The type of the root module. Remarks Use AspireApp{TModule}.RunAsync(string[]) when the root module is known at compile time and should participate in AppSurface dependency discovery, configuration registration, and host hooks. The new() constraint means TModule is activated by parameterless constructor rather than dependency injection, so keep constructors cheap, deterministic, and free of external side effects. Use AspireApp.RunAsync(string[]) when no root module is needed or module selection is driven by framework defaults. The call delegates to AspireAppStartup{TModule} for host activation. Method RunAsync Task RunAsync ( string[] args ) Runs the Aspire application asynchronously with the specified root module. Parameters args Command-line arguments. Returns A task representing the run operation. Type AspireAppStartup\u003CTModule\u003E Starts an Aspire AppHost with an AppSurface root module that implements IAppSurfaceHostModule . Type Parameters TModule The root AppSurface host module type for the Aspire AppHost. Remarks AspireAppStartup{TModule} is the Aspire-specific bootstrapper behind AspireApp{TModule}.RunAsync(string[]) . The new() constraint activates the root module with a parameterless constructor before dependency injection is available, so module constructors should avoid service resolution, blocking work, and disposable ownership. Host-module service registrations run through ConsoleStartup{TModule} before ConfigureAdditionalServices discovers Aspire components. Method ConfigureAdditionalServices void ConfigureAdditionalServices ( StartupContext context , IServiceCollection services ) Discovers IAspireComponent types from the entry assembly and registers each concrete type as a singleton. Parameters context The AppSurface startup context that supplies the entry assembly to scan. services The service collection receiving discovered Aspire component registrations. Remarks ConfigureAdditionalServices runs after the root IAppSurfaceHostModule and dependency modules have registered services. Components are registered by concrete type only, not by implemented interfaces, so consumers should resolve concrete component types directly. The registration is startup-only and does not transfer disposal ownership beyond normal container ownership.","snippet":"Type AspireStartupContext Provides context and helper methods during the Aspire application startup process. Method Resolve IResourceBuilder\u003CTResource\u003E Resolve \u003CTResource\u003E ( IAspireComponent\u003CTResource\u003E dependency )...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireApp","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireApp","title":"AspireApp","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire","AspireApp"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire#ForgeTrust-AppSurface-Aspire-AspireApp"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireApp-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireApp-1","title":"AspireApp\u003CTModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire","AspireApp\u003CTModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire#ForgeTrust-AppSurface-Aspire-AspireApp-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireAppStartup-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireAppStartup-1","title":"AspireAppStartup\u003CTModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire","AspireAppStartup\u003CTModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire#ForgeTrust-AppSurface-Aspire-AspireAppStartup-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireProfile","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireProfile","title":"AspireProfile","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire","AspireProfile"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire#ForgeTrust-AppSurface-Aspire-AspireProfile"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireStartupContext","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-AspireStartupContext","title":"AspireStartupContext","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire","AspireStartupContext"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire#ForgeTrust-AppSurface-Aspire-AspireStartupContext"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-IAspireComponent","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-IAspireComponent","title":"IAspireComponent","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire","IAspireComponent"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire#ForgeTrust-AppSurface-Aspire-IAspireComponent"},{"id":"Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-IAspireComponent-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Aspire.html#ForgeTrust-AppSurface-Aspire-IAspireComponent-1","title":"IAspireComponent\u003CT\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Aspire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Aspire","IAspireComponent\u003CT\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Aspire#ForgeTrust-AppSurface-Aspire-IAspireComponent-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Caching.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Caching.html","title":"Caching","summary":"Type AppSurfaceCachingModule A AppSurface module that registers the IMemo caching services. Type CachePolicy Describes the expiration behavior for a cached entry. Use the static factory methods to create common...","headings":["AppSurfaceCachingModule","CachePolicy","Absolute","Sliding","SlidingWithAbsolute","AbsoluteExpiration","SlidingExpiration","Memo","GetOrCreateCoreAsync","CreateEntryOptions","OnCacheEntryEvicted","Dispose","CachedFailure","IMemo","GetAsync"],"bodyText":"Type AppSurfaceCachingModule A AppSurface module that registers the IMemo caching services. Type CachePolicy Describes the expiration behavior for a cached entry. Use the static factory methods to create common configurations. Method Absolute CachePolicy Absolute ( TimeSpan duration ) Creates a policy that evicts the entry after a fixed duration from creation. Parameters duration The time after which the entry expires. Returns A CachePolicy with absolute expiration. Exceptions ArgumentOutOfRangeException Thrown when duration is not positive. Method Sliding CachePolicy Sliding ( TimeSpan window ) Creates a policy that evicts the entry if it is not accessed within the given window. Each access resets the sliding timer. Parameters window The idle duration after which the entry expires. Returns A CachePolicy with sliding expiration. Exceptions ArgumentOutOfRangeException Thrown when window is not positive. Method SlidingWithAbsolute CachePolicy SlidingWithAbsolute ( TimeSpan window , TimeSpan max ) Creates a policy that slides the entry on each access but enforces an absolute ceiling. The entry is evicted when it has been idle for window , or unconditionally after max from creation, whichever comes first. Parameters window The sliding idle window. max The absolute maximum lifetime. Returns A CachePolicy with both sliding and absolute expiration. Exceptions ArgumentOutOfRangeException Thrown when window or max is not positive. ArgumentException Thrown when window is greater than or equal to max . Property AbsoluteExpiration TimeSpan? AbsoluteExpiration { get; init; } Gets the absolute expiration duration. The entry is evicted after this duration regardless of access patterns. Property SlidingExpiration TimeSpan? SlidingExpiration { get; init; } Gets the sliding expiration window. The entry is evicted if not accessed within this duration. Each access resets the timer. Type Memo Memoizes async factory calls using IMemoryCache with automatic key generation and per-key thundering-herd protection. Method GetOrCreateCoreAsync Task\u003CTResult\u003E GetOrCreateCoreAsync \u003CTState, TResult\u003E ( object key , TState state , Func\u003CTState, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken ) Core implementation that handles cache lookup, thundering-herd synchronization, exception caching, and entry creation with the configured policy. Uses a state-passing pattern to avoid closure allocations on the hot path. key can be a ValueTuple for efficiency. Remarks null results from the factory are treated as valid cached values for reference types. Method CreateEntryOptions MemoryCacheEntryOptions CreateEntryOptions ( SemaphoreSlim keyLock ) Creates MemoryCacheEntryOptions with a post-eviction callback that removes the corresponding SemaphoreSlim from _locks to prevent unbounded growth. Parameters keyLock The specific semaphore instance to capture for reference-safe eviction cleanup. Method OnCacheEntryEvicted void OnCacheEntryEvicted ( object key , object? value , EvictionReason reason , object? state ) Post-eviction callback that cleans up the per-key semaphore from the locks dictionary. Only removes the exact semaphore instance that was captured when the cache entry was created, preserving any newer semaphore created by concurrent callers via GetOrAdd . Method Dispose void Dispose () Disposes the underlying locks. Type CachedFailure Sentinel wrapper stored in the cache when a factory invocation fails, allowing subsequent waiters to short-circuit instead of re-invoking the factory. Type IMemo Provides memoized, cache-backed access to expensive computations with automatic key generation and thundering-herd protection. Method GetAsync 18 overloads Task\u003CTResult\u003E GetAsync \u003CTResult\u003E ( Func\u003CTask\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path and line number. Type Parameters TResult The type of the cached value. Parameters factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTResult\u003E ( Func\u003CCancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path and line number. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TResult The type of the cached value. Parameters factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg, TResult\u003E ( TArg arg , Func\u003CTArg, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and arg . Type Parameters TArg The type of the argument. TResult The type of the cached value. Parameters arg The argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg, TResult\u003E ( TArg arg , Func\u003CTArg, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and arg . The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg The type of the argument. TResult The type of the cached value. Parameters arg The argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , Func\u003CTArg1, TArg2, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , Func\u003CTArg1, TArg2, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , Func\u003CTArg1, TArg2, TArg3, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , Func\u003CTArg1, TArg2, TArg3, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , Func\u003CTArg1, TArg2, TArg3, TArg4, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , Func\u003CTArg1, TArg2, TArg3, TArg4, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , TArg6 arg6 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TArg6 The type of the sixth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. arg6 The sixth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , TArg6 arg6 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TArg6 The type of the sixth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. arg6 The sixth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , TArg6 arg6 , TArg7 arg7 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TArg6 The type of the sixth argument. TArg7 The type of the seventh argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. arg6 The sixth argument passed to the factory and incorporated into the cache key. arg7 The seventh argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , TArg6 arg6 , TArg7 arg7 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TArg6 The type of the sixth argument. TArg7 The type of the seventh argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. arg6 The sixth argument passed to the factory and incorporated into the cache key. arg7 The seventh argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , TArg6 arg6 , TArg7 arg7 , TArg8 arg8 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TArg6 The type of the sixth argument. TArg7 The type of the seventh argument. TArg8 The type of the eighth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. arg6 The sixth argument passed to the factory and incorporated into the cache key. arg7 The seventh argument passed to the factory and incorporated into the cache key. arg8 The eighth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. policy The cache expiration policy. cancellationToken A token to cancel the cache lock acquisition. Returns The cached or freshly computed value. Task\u003CTResult\u003E GetAsync \u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult\u003E ( TArg1 arg1 , TArg2 arg2 , TArg3 arg3 , TArg4 arg4 , TArg5 arg5 , TArg6 arg6 , TArg7 arg7 , TArg8 arg8 , Func\u003CTArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, CancellationToken, Task\u003CTResult\u003E\u003E factory , CachePolicy policy , CancellationToken cancellationToken = default ) Returns a cached result or invokes factory to compute and cache it. The cache key is automatically derived from the caller file path, line number, and the provided arguments. The CancellationToken is forwarded to the factory for cooperative cancellation. Type Parameters TArg1 The type of the first argument. TArg2 The type of the second argument. TArg3 The type of the third argument. TArg4 The type of the fourth argument. TArg5 The type of the fifth argument. TArg6 The type of the sixth argument. TArg7 The type of the seventh argument. TArg8 The type of the eighth argument. TResult The type of the cached value. Parameters arg1 The first argument passed to the factory and incorporated into the cache key. arg2 The second argument passed to the factory and incorporated into the cache key. arg3 The third argument passed to the factory and incorporated into the cache key. arg4 The fourth argument passed to the factory and incorporated into the cache key. arg5 The fifth argument passed to the factory and incorporated into the cache key. arg6 The sixth argument passed to the factory and incorporated into the cache key. arg7 The seventh argument passed to the factory and incorporated into the cache key. arg8 The eighth argument passed to the factory and incorporated into the cache key. factory The async factory to compute the value on a cache miss. Receives a CancellationToken . policy The cache expiration policy. cancellationToken A token to cancel both lock acquisition and factory invocation. Returns The cached or freshly computed value.","snippet":"Type AppSurfaceCachingModule A AppSurface module that registers the IMemo caching services. Type CachePolicy Describes the expiration behavior for a cached entry. Use the static factory methods to create common...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Caching","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Caching"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Caching"},{"id":"Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-AppSurfaceCachingModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-AppSurfaceCachingModule","title":"AppSurfaceCachingModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Caching","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Caching","AppSurfaceCachingModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Caching#ForgeTrust-AppSurface-Caching-AppSurfaceCachingModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-CachePolicy","path":"/docs/Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-CachePolicy","title":"CachePolicy","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Caching","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Caching","CachePolicy"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Caching#ForgeTrust-AppSurface-Caching-CachePolicy"},{"id":"Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-IMemo","path":"/docs/Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-IMemo","title":"IMemo","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Caching","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Caching","IMemo"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Caching#ForgeTrust-AppSurface-Caching-IMemo"},{"id":"Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-Memo","path":"/docs/Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-Memo","title":"Memo","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Caching","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Caching","Memo"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Caching#ForgeTrust-AppSurface-Caching-Memo"},{"id":"Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-Memo-CachedFailure","path":"/docs/Namespaces/ForgeTrust.AppSurface.Caching.html#ForgeTrust-AppSurface-Caching-Memo-CachedFailure","title":"CachedFailure","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Caching","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Caching","CachedFailure"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Caching#ForgeTrust-AppSurface-Caching-Memo-CachedFailure"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html","title":"Cli","summary":"Type AppSurfaceCliModule Represents the AppSurface CLI root module used to bootstrap command execution. Remarks The module is intentionally empty today: the CLI owns command registration in AppSurfaceCliApp and...","headings":["AppSurfaceCliModule","ConfigureServices","ConfigureHostBeforeServices","ConfigureHostAfterServices","RegisterDependentModules","ProgramEntryPoint","RunAsync","PushConfigureOptionsOverrideForTests","RestoreOverrideScope","DocsCommand","DocsPreviewCommand","RazorDocsPreviewCommand","ExecuteAsync","BuildHostArgs","RepositoryRoot","Urls","Port","StrictHarvest","RouteRootPath","DocsRootPath","EnvironmentName","StartupTimeoutSeconds","RazorDocsHostArgs","IRazorDocsHostRunner"],"bodyText":"Type AppSurfaceCliModule Represents the AppSurface CLI root module used to bootstrap command execution. Remarks The module is intentionally empty today: the CLI owns command registration in AppSurfaceCliApp and delegates web-host behavior to RazorDocs-specific runners. Add dependencies here only when every AppSurface CLI command needs the same module-level dependency graph or host lifecycle hook. Prefer command-local services or custom test registrations for isolated behavior, and do not place runtime command logic in this module. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Configures shared CLI services after the default command runtime registrations have been added. Parameters context Startup context for the CLI run. services Service collection that will back command construction. Remarks The default implementation is a no-op. Keep it empty unless a service truly applies to the whole CLI surface. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , IHostBuilder builder ) Configures a Generic Host builder before services are registered. Parameters context Startup context for the CLI run. builder Host builder that would be configured by host-based startup paths. Remarks The command runtime does not currently build a Generic Host through this module, so this hook is intentionally a no-op and exists to satisfy the shared AppSurface host-module contract. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , IHostBuilder builder ) Configures a Generic Host builder after services are registered. Parameters context Startup context for the CLI run. builder Host builder that would be configured by host-based startup paths. Remarks Keep this empty until the CLI adopts a host-backed lifecycle. Command behavior should stay in command classes. Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers root-module dependencies for the AppSurface CLI module graph. Parameters builder Dependency builder used by AppSurface startup composition. Remarks The CLI has no module dependencies by default. Add dependencies here only for cross-command infrastructure that must participate in AppSurface module ordering. Type ProgramEntryPoint Internal CLI entry point that adds a scoped test seam around AppSurfaceCliApp . Remarks Production code uses RunAsync directly. Tests can use PushConfigureOptionsOverrideForTests to add temporary console or DI overrides without changing the top-level statement in Program.cs . Method RunAsync Task RunAsync ( string[] args , Action\u003CConsoleOptions\u003E? configureOptions = null ) Runs the AppSurface CLI with the specified arguments and optional console configuration. Parameters args Command-line arguments to parse and execute. configureOptions Optional primary console-options callback for the current invocation. Returns A task that represents the CLI execution. Method PushConfigureOptionsOverrideForTests IDisposable PushConfigureOptionsOverrideForTests ( Action\u003CConsoleOptions\u003E configureOptions ) Pushes a test-only console-options override for the current async context. Parameters configureOptions Override callback to apply after any direct invocation callback. Returns A disposable scope that restores the previous override when disposed. Remarks Always dispose the returned scope, typically with using var . Overrides compose with RunAsync callbacks in direct-then-override order so tests can replace services after production defaults are configured. Type RestoreOverrideScope Restores the previously active test override when disposed. Parameters previous Override that was active before the current scope was pushed. Type DocsCommand Previews RazorDocs for a local repository through the public appsurface docs command. Remarks This command starts the RazorDocs standalone host with CLI-friendly defaults and delegates option validation and argument construction to RazorDocsPreviewCommand . Type DocsPreviewCommand Previews RazorDocs for a local repository through the appsurface docs preview alias. Remarks Use this alias when a command hierarchy reads better in scripts. It has the same options and behavior as DocsCommand . Type RazorDocsPreviewCommand Shared implementation for RazorDocs preview commands. Remarks The base command translates CLI options into RazorDocs standalone host arguments. It keeps command parsing separate from process hosting so tests can verify validation and argument forwarding without starting Kestrel. Method ExecuteAsync 2 overloads ValueTask ExecuteAsync ( IConsole console ) Executes the command through the CliFx console integration. Parameters console Console abstraction used to register cancellation handling. Returns A value task that completes when the preview host exits or command validation fails. ValueTask ExecuteAsync ( CancellationToken cancellationToken ) Executes the command using an explicit cancellation token. Parameters cancellationToken Token observed before the host runner starts. Returns A value task that completes when the preview host exits. Remarks This overload exists for tests and shared command execution paths that already own cancellation registration. Method BuildHostArgs RazorDocsHostArgs BuildHostArgs () Translates CLI options into standalone RazorDocs host arguments. Returns The repository root, forwarded host arguments, and startup timeout for the preview run. Remarks This method performs command-level validation so users receive CommandException errors before the web host starts. It is internal so tests can verify the translation contract without opening a listener. Property RepositoryRoot string RepositoryRoot { get; init; } Gets the repository root to harvest and preview. Remarks Defaults to the current directory. Use this when running the CLI from a parent directory, script workspace, or package output folder. The value must resolve to an existing directory. Property Urls string? Urls { get; init; } Gets the explicit URL binding forwarded to the RazorDocs host. Remarks Use this for a full Kestrel binding such as http://127.0.0.1:5189 . Prefer Port when only the port needs to change. Property Port int? Port { get; init; } Gets the port shortcut forwarded to the RazorDocs host. Remarks Use this for local preview scripts that only need a port override. Use Urls for explicit host, scheme, or multi-binding scenarios. Property StrictHarvest bool StrictHarvest { get; init; } Gets a value indicating whether startup should fail when every configured RazorDocs harvester fails. Remarks Keep this off for exploratory local preview. Enable it in CI or release checks where a completely failed harvest should stop the command before the site starts. Property RouteRootPath string? RouteRootPath { get; init; } Gets the route-family root for RazorDocs version and archive routes. Remarks Use this when the docs route family is mounted somewhere other than /docs , for example --route-root /reference . Pair it with DocsRootPath when the live preview path should differ from archive/version routes. Property DocsRootPath string? DocsRootPath { get; init; } Gets the live docs preview root path. Remarks Use this to preview current docs under a nested route, for example --route-root /reference --docs-root /reference/next . Leave unset to use RazorDocs defaults. Property EnvironmentName string? EnvironmentName { get; init; } Gets the host environment forwarded to the RazorDocs standalone host. Remarks Use Development for local preview diagnostics and development defaults. Leave unset to let the host choose its normal environment from command-line and process configuration. Property StartupTimeoutSeconds double StartupTimeoutSeconds { get; init; } Gets the number of seconds to wait for the web host to start before failing fast. Remarks Defaults to 30 seconds. Set to 0 to disable the startup watchdog. Negative, infinite, and NaN values are rejected before the host starts. Type RazorDocsHostArgs Describes the RazorDocs host invocation produced by the CLI option translator. Parameters RepositoryRoot Absolute repository root that the RazorDocs host should harvest. Args Command-line arguments forwarded to the standalone RazorDocs host. StartupTimeout Startup watchdog timeout, or null when disabled. Type IRazorDocsHostRunner Starts a RazorDocs host for CLI preview commands. Remarks This seam keeps command parsing and validation testable without starting a real web host. Production implementations should honor cancellation before delegating into long-running host lifetimes. Method RunAsync Task RunAsync ( string[] args , TimeSpan? startupTimeout , CancellationToken cancellationToken ) Runs the RazorDocs host with translated command-line arguments. Parameters args Arguments forwarded to the standalone RazorDocs host. startupTimeout Startup watchdog timeout, or null to disable it. cancellationToken Token that cancels before the host is started. Returns A task that completes when the host exits. Type RazorDocsStandaloneHostRunner Production IRazorDocsHostRunner that delegates to the standalone RazorDocs web host. Remarks Use this adapter for the packaged AppSurface CLI path. Tests should prefer fake runners so they can verify argument translation without starting Kestrel. The type is internal and sealed because callers should depend on IRazorDocsHostRunner rather than subclassing host lifetime behavior. Type AppSurfaceCliApp Provides the DI-backed execution runtime for AppSurface CLI commands. Remarks This internal runtime exists so the top-level tool entry point stays thin while command discovery, dependency registration, logging defaults, and CliFx execution stay testable. It discovers commands from the AppSurface CLI entry assembly, applies module and caller-provided service registrations, temporarily assigns CommandService.PrimaryServiceProvider for constructor-injected command dependencies, and always restores the previous provider after command execution. Method RunAsync Task RunAsync ( string[] args , Action\u003CConsoleOptions\u003E? configureOptions = null ) Runs the AppSurface CLI with the provided command-line arguments. Parameters args Command-line arguments to parse and execute. configureOptions Optional callback that customizes ConsoleOptions before execution. Defaults start from ConsoleOptions.Default with ConsoleOutputMode.CommandFirst so command output remains the primary console experience. Returns A task that completes when the selected command finishes. Remarks Use this seam from process entry points and tests that need the real command pipeline without shelling out. The method builds and disposes a fresh service provider for each run, registers AppSurface CLI defaults, then applies custom registrations last so tests or future host integrations can replace defaults intentionally.","snippet":"Type AppSurfaceCliModule Represents the AppSurface CLI root module used to bootstrap command execution. Remarks The module is intentionally empty today: the CLI owns command registration in AppSurfaceCliApp and...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-AppSurfaceCliApp","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-AppSurfaceCliApp","title":"AppSurfaceCliApp","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","AppSurfaceCliApp"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-AppSurfaceCliApp"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-AppSurfaceCliModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-AppSurfaceCliModule","title":"AppSurfaceCliModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","AppSurfaceCliModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-AppSurfaceCliModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-DocsCommand","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-DocsCommand","title":"DocsCommand","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","DocsCommand"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-DocsCommand"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-DocsPreviewCommand","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-DocsPreviewCommand","title":"DocsPreviewCommand","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","DocsPreviewCommand"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-DocsPreviewCommand"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-IRazorDocsHostRunner","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-IRazorDocsHostRunner","title":"IRazorDocsHostRunner","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","IRazorDocsHostRunner"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-IRazorDocsHostRunner"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-ProgramEntryPoint","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-ProgramEntryPoint","title":"ProgramEntryPoint","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","ProgramEntryPoint"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-ProgramEntryPoint"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-ProgramEntryPoint-RestoreOverrideScope","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-ProgramEntryPoint-RestoreOverrideScope","title":"RestoreOverrideScope","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","RestoreOverrideScope"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-ProgramEntryPoint-RestoreOverrideScope"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-RazorDocsHostArgs","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-RazorDocsHostArgs","title":"RazorDocsHostArgs","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","RazorDocsHostArgs"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-RazorDocsHostArgs"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-RazorDocsPreviewCommand","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-RazorDocsPreviewCommand","title":"RazorDocsPreviewCommand","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","RazorDocsPreviewCommand"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-RazorDocsPreviewCommand"},{"id":"Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-RazorDocsStandaloneHostRunner","path":"/docs/Namespaces/ForgeTrust.AppSurface.Cli.html#ForgeTrust-AppSurface-Cli-RazorDocsStandaloneHostRunner","title":"RazorDocsStandaloneHostRunner","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Cli","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Cli","RazorDocsStandaloneHostRunner"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Cli#ForgeTrust-AppSurface-Cli-RazorDocsStandaloneHostRunner"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html","title":"Config","summary":"Type ConfigScalarTypes Provides the canonical scalar-type classification shared by configuration validation paths. Method IsScalar bool IsScalar ( Type type ) Returns whether type is treated as a scalar configuration...","headings":["ConfigScalarTypes","IsScalar","ConfigAuditRedactor","CreatePolicy","FormatValue","RedactedValue","EnvironmentConfigProvider","NormalizeSegment","NormalizeHierarchicalKey","ConfigAuditKnownEntry","Key","ConfigType","ValueType","ConfigAuditServiceCollectionExtensions","AddConfigAuditKey","IConfigProvider","GetValue","Priority","Name","ConfigurationValidationException","Failures","Config\u003CT\u003E","Init","ValidateValue"],"bodyText":"Type ConfigScalarTypes Provides the canonical scalar-type classification shared by configuration validation paths. Method IsScalar bool IsScalar ( Type type ) Returns whether type is treated as a scalar configuration value. Nullable wrappers are unwrapped before inspection. Supported scalar types are primitives, enums, string , decimal , DateTime , DateTimeOffset , TimeSpan , Guid , and Uri . Parameters type The declared or runtime value type to inspect. Returns true when type is a supported scalar type. Type ConfigAuditRedactor Applies the built-in audit redaction and value formatting policy. Remarks Matching is fragment based and case-insensitive across keys, config paths, applied paths, and environment variable names. Sensitive values are replaced with a fixed placeholder before rendering. Non-sensitive complex objects may produce a null display value so callers can rely on child entries instead of an unsafe dump. Formatting failures are swallowed intentionally to keep audit generation best-effort. Method CreatePolicy ConfigAuditRedaction CreatePolicy () Creates a snapshot of the redaction policy applied to reports. Returns A policy snapshot with a copy of the sensitive fragments and the placeholder text. Method FormatValue RedactedValue FormatValue ( string key , object? value , IReadOnlyList\u003CConfigAuditSourceRecord\u003E sources ) Formats value for display and redacts it when the key or sources look sensitive. Parameters key The configuration key being formatted. value The resolved value, if any. sources The sources that contributed to the value. Returns The display value and whether it was replaced by the redaction placeholder. Type RedactedValue Describes a formatted value after applying the redaction policy. Parameters DisplayValue The safe display value, or null for non-scalar objects. IsRedacted A value indicating whether the placeholder replaced the original value. Type EnvironmentConfigProvider A configuration provider that retrieves values from environment variables. Method NormalizeSegment string NormalizeSegment ( string value ) Converts a key/environment segment to uppercase (via string.ToUpperInvariant ) and flattens separators by replacing \u0027.\u0027 and \u0027-\u0027 with a single \u0027_\u0027. Used for legacy flat environment-variable lookup. Method NormalizeHierarchicalKey string NormalizeHierarchicalKey ( string value ) Converts a key to uppercase (via string.ToUpperInvariant ), splits on \u0027.\u0027 and \u0027-\u0027 as hierarchical delimiters, removes empty segments, and joins segments using \u0022__\u0022. Used for hierarchical environment-variable lookup while preserving path boundaries. Type ConfigAuditKnownEntry Describes a configuration entry known to AppSurface\u0027s audit system. Property Key string Key { get; } Gets the configuration key. Property ConfigType Type? ConfigType { get; } Gets the config wrapper type, when this entry came from a wrapper. Property ValueType Type ValueType { get; } Gets the declared value type. Type ConfigAuditServiceCollectionExtensions Extension methods for registering additional configuration audit keys. Method AddConfigAuditKey IServiceCollection AddConfigAuditKey \u003CT\u003E ( this IServiceCollection services , string key ) Registers an additional configuration key for audit reports. Type Parameters T The expected value type. Parameters services The service collection. key The configuration key. Returns The original services instance. Remarks Use this method for values that should appear in audit reports but are not backed by an IConfig or Config{T} wrapper discovered by assembly scanning. Prefer wrapper discovery when a typed wrapper already exists, because the wrapper can contribute defaults and validation diagnostics. Manual registration creates a ConfigAuditKnownEntry with ConfigAuditKnownEntry.ConfigType set to null and T as the expected value type; for example, AddConfigAuditKey\u003CUri\u003E(\u0022Billing.Endpoint\u0022) includes a provider-only key in reports. Type IConfigProvider Defines a provider that can retrieve configuration values. Method GetValue T? GetValue \u003CT\u003E ( string environment , string key ) Retrieves a configuration value for a specific environment and key. Type Parameters T The type of the configuration value. Parameters environment The environment name (e.g., \u0022Production\u0022). key The configuration key. Returns The configuration value, or the default value of T if not found. Property Priority int Priority { get; } Higher number means higher priority. When multiple providers provide the same key, the one with the highest priority wins. Property Name string Name { get; } Gets the name of the configuration provider. Type ConfigurationValidationException The exception thrown when a strongly typed configuration value fails validation during initialization. Property Key string Key { get; } Gets the configuration key being initialized. Property ConfigType Type ConfigType { get; } Gets the concrete configuration wrapper type being initialized. Property ValueType Type ValueType { get; } Gets the resolved value type that was validated. Property Failures IReadOnlyList\u003CConfigurationValidationFailure\u003E Failures { get; } Gets the validation failures returned for the configuration value. Type Config\u003CT\u003E A base class for strongly-typed configuration objects. Values are resolved during IConfig.Init , then object-valued configuration models are validated with DataAnnotations and scalar values can be validated with AppSurface scalar attributes or ValidateValue . Invalid provider values and invalid defaults fail fast by throwing ConfigurationValidationException , so callers that activate config wrappers can catch that exception and surface its structured failures. Ensure defaults satisfy the same validation rules as configured values; an invalid default prevents initialization when no provider value exists. Apply ConfigKeyRequiredAttribute to require resolved provider/default presence. Type Parameters T The type of the configuration value. Method Init void Init ( IConfigManager configManager , IEnvironmentProvider environmentProvider , string key ) Resolves the configured value for key and validates the resolved provider value or DefaultValue before initialization completes. Parameters configManager The configuration manager used to resolve the provider value. environmentProvider The environment provider used to choose the active environment. key The configuration key to resolve. Exceptions ConfigurationValidationException Thrown when the wrapper requires a value and no provider/default value resolves, or when the provider value or default value violates object DataAnnotations or scalar validation rules. Method ValidateValue IEnumerable\u003CValidationResult\u003E? ValidateValue ( T value , ValidationContext validationContext ) Validates a resolved non-null scalar configuration value. Override this method when a scalar rule is too specific for the built-in AppSurface scalar attributes. Parameters value The resolved provider or default scalar value. validationContext The validation context for the concrete configuration wrapper. Returns The validation results for value . Return null , an empty sequence, ValidationResult.Success , or null entries when validation succeeds. Property HasValue bool HasValue { get; set; } Gets a value indicating whether the configuration has a value (either from source or default). Property IsDefaultValue bool IsDefaultValue { get; set; } Gets a value indicating whether the current value is the default value. Property Value T? Value { get; set; } Gets the configuration value. Property DefaultValue T? DefaultValue { get; } Gets the default value for the configuration if none is found in the source. Type ConfigKeyRequiredAttribute Requires a strongly typed configuration wrapper to resolve a value during initialization. Remarks Apply this attribute to a concrete Config{T} or ConfigStruct{T} wrapper when startup should fail if provider/default resolution leaves the wrapper without a value. A Config{T}.DefaultValue or ConfigStruct{T}.DefaultValue satisfies the requirement because the requirement is resolved presence, not provider-source auditing. This attribute is intentionally separate from scalar value validation attributes such as ConfigValueNotEmptyAttribute . Use ConfigKeyRequiredAttribute when absence should fail, and use value validation when a resolved value must satisfy shape or range rules. Type ConfigurationValidationFailure Describes one validation failure found while initializing a strongly typed configuration value. Property Key string Key { get; } Gets the configuration key being initialized. Property ConfigType Type ConfigType { get; } Gets the concrete configuration wrapper type being initialized. Property ValueType Type ValueType { get; } Gets the resolved value type that was validated. Property MemberNames IReadOnlyList\u003Cstring\u003E MemberNames { get; } Gets the member names or paths associated with the failure. Object-level failures use an empty list rather than null; consumers should treat that empty collection as a valid failure payload. The returned list is an immutable snapshot owned by this instance. Property Message string Message { get; } Gets the validation message. Type IConfigValuePatcher Provides object-graph patching for configuration providers that can supply child values beneath a requested key. Remarks This is an internal provider seam, not a consumer-facing configuration API. DefaultConfigManager uses it after direct provider resolution so hierarchical override sources can update only the supplied child values instead of replacing an entire options object. Method TryPatch bool TryPatch \u003CT\u003E ( string environment , string key , T? currentValue , out T? patchedValue ) Attempts to apply provider-owned child values beneath key to currentValue . Type Parameters T The requested configuration value type. Parameters environment The active environment name. key The configuration key whose child values may be present. currentValue The value supplied by a lower-priority provider, or default . patchedValue When this method returns true , contains the patched value. Otherwise contains default . Returns true when at least one child value was applied. Type ConfigAuditTextRenderer Renders ConfigAuditReport instances as deterministic, human-readable text. Method Render string Render ( ConfigAuditReport report ) Renders report as text. Parameters report The report to render. Returns A human-readable report. Type AppSurfaceConfigModule A module that registers configuration management services and automatically discovers and registers configuration objects. Remarks AppSurfaceConfigModule registers core configuration services immediately, then defers typed IConfig discovery through StartupContext.CustomRegistrations so all module dependencies are known first. The deferred scan inspects dependency module assemblies, the entry assembly, and the root module assembly. Pitfall: config dependencies should be registered before the custom registration callback runs; otherwise discovered config objects may activate before their supporting services are available. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Registers AppSurface config services and schedules typed config discovery after module registration. Parameters context Startup context that supplies assemblies, dependency modules, and the custom registration log. services Service collection that receives the default configuration services. Remarks ConfigureServices(StartupContext, IServiceCollection) adds the default manager, providers, audit reporter, redactor, and file-location provider, then appends a StartupContext.CustomRegistrations callback. That callback scans dependency, entry, and root-module assemblies for concrete IConfig implementations and registers each as a singleton initialized from IConfigManager and IEnvironmentProvider . Type ConfigDataAnnotationsValidator Validates resolved Config{T} and ConfigStruct{T} values with DataAnnotations. The validator returns immediately for null values and scalar primitives, validates object and field annotations before initialization completes, and traverses nested members only when callers opt in with ValidateObjectMembersAttribute or ValidateEnumeratedItemsAttribute . Recursive traversal tracks the active object path by reference so cycles terminate while shared objects can still be reported at each reachable path. AppSurface owns this traversal and the ConfigurationValidationException shape; the custom validator type overloads on the Microsoft Options marker attributes are reported as unsupported failures rather than invoked. Method Validate void Validate ( string key , Type configType , Type valueType , object? value ) Validates a resolved configuration value and throws ConfigurationValidationException when DataAnnotations failures are found. Call this after provider/default resolution and before config initialization is considered complete. Null and scalar values short-circuit, recursive validation is marker-gated, and callers should catch ConfigurationValidationException to inspect the structured failures. Parameters key The configuration key being initialized. configType The concrete configuration wrapper type being initialized. valueType The resolved value type that is being validated. value The resolved provider or default value. Exceptions ConfigurationValidationException Thrown when the resolved value or an opted-in nested value violates DataAnnotations validation rules. Type ConfigKeyAttribute Specifies the configuration key or path for a type. Method ExtractKey 2 overloads string? ExtractKey ( object obj ) Extracts the configuration key from an object\u0027s type attribute. Parameters obj The object to extract the key from. Returns The configuration key, or null if not specified. string? ExtractKey ( Type type ) Extracts the configuration key from a type\u0027s attribute. Parameters type The type to extract the key from. Returns The configuration key, or null if not specified. Method GetKeyPath string GetKeyPath ( Type type ) Computes the full configuration key path for a type, recursively including declaring types unless Root is true. Parameters type The type to compute the path for. Returns The computed configuration key path. Property Key string Key { get; } Gets the configuration key or path for this type. Property Root bool Root { get; } Gets a value indicating whether this key should be treated as a root key, ignoring the declaring type hierarchy. Type FileBasedConfigProvider A configuration provider that reads settings from JSON files (e.g., appsettings.json, config_*.json). Type ConfigStruct\u003CT\u003E A base class for strongly-typed configuration objects where the value is a struct. Values are resolved during IConfig.Init , then object-valued configuration models are validated with DataAnnotations and scalar values can be validated with AppSurface scalar attributes or ValidateValue . Invalid provider values and invalid defaults fail fast by throwing ConfigurationValidationException , so callers that activate config wrappers can catch that exception and surface its structured failures. Ensure defaults satisfy the same validation rules as configured values; an invalid default prevents initialization when no provider value exists. Apply ConfigKeyRequiredAttribute to require resolved provider/default presence. Type Parameters T The struct type of the configuration value. Method Init void IConfig. Init ( IConfigManager configManager , IEnvironmentProvider environmentProvider , string key ) Resolves the configured value for key and validates the resolved provider value or DefaultValue before initialization completes. Parameters configManager The configuration manager used to resolve the provider value. environmentProvider The environment provider used to choose the active environment. key The configuration key to resolve. Exceptions ConfigurationValidationException Thrown when the wrapper requires a value and no provider/default value resolves, or when the provider value or default value violates object DataAnnotations or scalar validation rules. Method ValidateValue IEnumerable\u003CValidationResult\u003E? ValidateValue ( T value , ValidationContext validationContext ) Validates a resolved non-null scalar configuration value. Override this method when a scalar rule is too specific for the built-in AppSurface scalar attributes. Parameters value The resolved provider or default scalar value. validationContext The validation context for the concrete configuration wrapper. Returns The validation results for value . Return null , an empty sequence, ValidationResult.Success , or null entries when validation succeeds. Property HasValue bool HasValue { get; set; } Gets a value indicating whether the configuration has a value. Property IsDefaultValue bool IsDefaultValue { get; set; } Gets a value indicating whether the current value is the default value. Property Value T? Value { get; set; } Gets the configuration value. Property DefaultValue T? DefaultValue { get; } Gets the default value for the configuration if none is found in the source. Type ConfigPresenceValidator Validates required resolved presence for strongly typed configuration wrappers. Method Validate void Validate ( string key , Type configType , Type valueType , bool hasValue ) Throws ConfigurationValidationException when a wrapper marked with ConfigKeyRequiredAttribute has no resolved provider or default value. Parameters key The configuration key being initialized. configType The concrete configuration wrapper type being initialized. valueType The declared configuration value type. hasValue Whether provider/default resolution produced a value. Type IEnvironmentConfigProvider Defines a configuration provider that also provides environment information. Remarks IEnvironmentConfigProvider composes IConfigProvider with IEnvironmentProvider for implementations that need to resolve configuration and the active environment from the same source. Prefer the composite when environment-aware config lookup should be atomic or co-located in one implementation; use the separate interfaces when configuration and environment ownership differ. Implementations should be safe for repeated reads, define any caching or refresh behavior, and avoid assuming that all configuration is environment-exclusive. Disposal and lifetime follow the concrete provider registration. Type IConfigAuditReporter Produces structured configuration audit reports. Remarks Reporters inspect known configuration keys, provider provenance, validation diagnostics, and redacted display values. Implementations should return a report with diagnostics for recoverable provider and wrapper failures rather than throwing after argument validation succeeds. Method GetReport ConfigAuditReport GetReport ( string environment ) Builds a configuration audit report for environment . Parameters environment The environment to audit. Returns The completed audit report. Type ConfigAuditReporter Default implementation that mirrors configuration resolution while preserving source and diagnostic metadata. Remarks This internal reporter treats IEnvironmentConfigProvider as the override provider, excludes manager/internal provider registrations from the displayed provider list, and favors wrapper-discovered audit entries when duplicate keys are registered manually. Provider failures are converted into diagnostics so one broken provider does not prevent operators from seeing the rest of the report. Type ConfigValueResolution Captures a provider\u0027s value resolution result before wrapper inspection and redaction. Parameters Key The configuration key being resolved. State The provider-level resolution state. Value The resolved raw value, or null when missing or invalid. Sources The sources that contributed to the value. Diagnostics Diagnostics emitted while resolving the value. Remarks The reporter uses this internal contract to keep value state, provenance, and diagnostics together while it walks providers in precedence order. Missing values should be represented with Missing(string) . Method Missing ConfigValueResolution Missing ( string key ) Creates a missing resolution with a synthetic missing source record for key . Parameters key The missing configuration key. Returns A missing resolution that can still be rendered with provenance. Type ConfigPatchDiagnosticResult Describes the result of tracing environment patches onto an existing provider value. Parameters Patched A value indicating whether any member was patched. Value The patched value, or the original/current value when unchanged. Sources The environment sources that successfully patched the value. Diagnostics Diagnostics produced while reading patch candidates. Type ConfigWrapperInspection Describes wrapper inspection after provider resolution. Parameters Value The value to display and expand after defaulting or validation. State The wrapper-adjusted state, or null to keep provider state. DefaultSource The default source when the wrapper supplied a fallback value. Diagnostics Validation and wrapper diagnostics. Type IConfigDiagnosticProvider Allows providers to expose audit-specific resolution details and report-level diagnostics. Remarks Implementations should avoid throwing for expected parse or source errors and return diagnostics instead. The reporter catches unexpected exceptions and converts them into provider diagnostics. Method Resolve ConfigValueResolution Resolve ( string environment , string key , Type valueType , ConfigAuditSourceRole role ) Resolves key for audit reporting without losing source metadata. Parameters environment The environment being audited. key The configuration key. valueType The expected value type. role The role the provider plays in final resolution. Returns The provider-specific resolution result. Method GetReportDiagnostics IReadOnlyList\u003CConfigAuditDiagnostic\u003E GetReportDiagnostics ( string environment ) Gets diagnostics that apply to the whole report rather than one key. Parameters environment The environment being audited. Returns Report-level diagnostics. Return an empty list when there are none. Type IConfigDiagnosticPatcher Allows an override provider to trace member-level patches onto a base provider value. Remarks The environment provider uses this to explain mixed provenance for object values without mutating the provider instance that supplied the base value. Method TracePatch ConfigPatchDiagnosticResult TracePatch ( string environment , string key , object? currentValue , Type valueType ) Traces patch candidates for key and returns a cloned patched value when possible. Parameters environment The environment being audited. key The configuration key. currentValue The lower-priority provider value to patch, when any. valueType The expected value type. Returns The patch result, including successful patch sources and diagnostics. Type IConfigInspectable Allows config wrappers to add defaults and validation diagnostics to an audit entry. Remarks Implementations receive the raw provider value and should return structured diagnostics rather than throwing for validation failures. Unexpected exceptions are caught by the wrapper implementations. Method Inspect ConfigWrapperInspection Inspect ( string key , object? rawValue , ConfigAuditEntryState resolutionState ) Inspects a resolved value for defaults and validation. Parameters key The configuration key. rawValue The raw provider value, or null when missing. resolutionState The state determined during provider resolution. Returns The wrapper inspection result. Type IConfigFileLocationProvider Provides the base directory used to resolve AppSurface configuration files. Remarks Implementations should return a stable absolute path that exists and is readable by the process. The default implementation returns AppContext.BaseDirectory . Callers should validate Directory before opening files and report a configuration error when it is null, empty, missing, unreadable, or unsuitable for the current platform. Paths should not depend on the current working directory; symlinks and platform separators are implementation details callers should normalize before comparison. Property Directory string Directory { get; } Gets the absolute directory path containing configuration files. Remarks The value should be an absolute path without a required trailing slash. The provider does not own the directory lifetime and should not create, delete, or lock it. A typical consumer checks System.IO.Directory.Exists(provider.Directory) before resolving known config file names below that path and returns a clear validation failure when the directory is unavailable. Type DefaultConfigFileLocationProvider Default implementation of IConfigFileLocationProvider that uses the application\u0027s base directory. Remarks DefaultConfigFileLocationProvider returns AppContext.BaseDirectory from Directory . This is appropriate for simple apps that keep configuration beside application binaries. Use a custom IConfigFileLocationProvider for environment-specific, user-scoped, container-mounted, or service-hosted configuration. Pitfall: AppContext.BaseDirectory is not necessarily System.IO.Directory.GetCurrentDirectory and can vary by deployment model, test runner, or host. Type ConfigValueValidationAttribute Base class for AppSurface scalar configuration value validation attributes. Apply derived attributes to concrete Config{T} or ConfigStruct{T} wrapper types to validate resolved scalar values during configuration initialization. Remarks Scalar validation runs after provider/default resolution and only when the resolved value is non-null. These attributes validate the value itself; they do not make a missing configuration key required. Use a default value or an application startup presence check when absence should fail. Validation is intentionally strict about value types. Built-in scalar attributes return validation failures for unsupported runtime types instead of converting values. Use an options object with DataAnnotations when validation spans multiple members, needs nested object traversal, or should model required presence separately from value shape. The validation context object is the concrete config wrapper and does not provide application dependency injection services. Override Config{T}.ValidateValue or ConfigStruct{T}.ValidateValue for scalar rules that cannot be expressed as reusable attributes. Type ConfigValueNotEmptyAttribute Validates that a resolved scalar configuration value is not empty. Supported value types are string and Guid . Remarks A null value is treated as successful validation so optional or missing scalar values remain optional. Non-null strings must contain non-whitespace characters, and non-null Guid values must not be Guid.Empty . Runtime type matching is strict: only string and Guid are supported. Applying this attribute to a different scalar value type returns a validation failure rather than attempting a conversion. Use an options object with member-level DataAnnotations when required presence, cross-field rules, or richer object validation is part of the contract. Type ConfigValueRangeAttribute Validates that a resolved scalar numeric configuration value is inside an inclusive range. Supported value types are int and double . Remarks A null value is treated as successful validation so optional or missing scalar values remain optional. Non-null values are compared against the inclusive minimum and maximum supplied to the constructor. Range validation accepts resolved int and double values. Integer bounds are widened when validating a double value, so attribute arguments such as [ConfigValueRange(1, 5)] work for ConfigStruct\u003Cdouble\u003E wrappers. Unsupported runtime types return validation failures instead of being converted. Use an options object when validation needs multiple numeric fields, required presence, or object-level DataAnnotations. Property Minimum object Minimum { get; } Gets the inclusive minimum allowed value as a boxed int or double , matching the constructor overload used to create the attribute. Remarks The integer constructor stores a boxed int , and the double constructor stores a boxed double . Callers should unbox this value according to the constructor overload they used. The attribute treats the bound as inclusive and may widen integer bounds when validating double values. Property Maximum object Maximum { get; } Gets the inclusive maximum allowed value as a boxed int or double , matching the constructor overload used to create the attribute. Remarks The integer constructor stores a boxed int , and the double constructor stores a boxed double . Callers should unbox this value according to the constructor overload they used. The attribute treats the bound as inclusive and may widen integer bounds when validating double values. Type ConfigValueMinLengthAttribute Validates that a resolved scalar string configuration value has at least the configured length. Remarks A null value is treated as successful validation so optional or missing scalar values remain optional. Non-null strings must have a length greater than or equal to Length . Runtime type matching is strict: only string values are supported. Applying this attribute to another scalar value type returns a validation failure rather than converting the value. Use an options object with DataAnnotations when string length is only one part of a larger model contract or when required presence should be represented separately. Property Length int Length { get; } Gets the minimum allowed string length. Type DefaultConfigManager Default implementation of IConfigManager that aggregates configuration from multiple sources. Method LogKeyNotFound void LogKeyNotFound ( string key , string environment ) Logs that a configuration key was not found. Parameters key The configuration key. environment The environment name. Method LogRetrievedFromEnvironment void LogRetrievedFromEnvironment ( string key , string environment , string source ) Logs that a configuration key was retrieved from a specific source. Parameters key The configuration key. environment The environment name. source The source of the configuration value. Type ConfigValidationFailureFactory Creates ConfigurationValidationFailure instances from DataAnnotations results while preserving AppSurface\u0027s member-path formatting contract. Method FromValidationResult ConfigurationValidationFailure FromValidationResult ( string key , Type configType , Type valueType , string? path , ValidationResult result , string? defaultMemberName = null ) Converts a ValidationResult into a configuration-validation failure payload. Parameters key The configuration key being validated. configType The concrete configuration wrapper type. valueType The resolved value type being validated. path Optional member path prefix. When present, validation-result member names are combined under this path using dot notation, and the path itself is used when the result has no member names. result The validation result to convert. defaultMemberName Optional fallback member name used when result has no member names, such as field-level validation where DataAnnotations did not bind the member name itself. Returns A normalized ConfigurationValidationFailure . Type IConfig Defines a configuration object that can be initialized using a configuration manager. Method Init void Init ( IConfigManager configManager , IEnvironmentProvider environmentProvider , string key ) Initializes the configuration object, resolving its provider or default value and failing fast with ConfigurationValidationException when required presence is not satisfied or when the resolved value violates object DataAnnotations rules or scalar value validation rules. Exceptions thrown by scalar Config{T}.ValidateValue or ConfigStruct{T}.ValidateValue overrides are not wrapped, so callers that activate config wrappers during startup should let unexpected programming errors fail the startup path. Parameters configManager The configuration manager to use for retrieving values. environmentProvider The environment provider. key The root configuration key for this object. Exceptions ConfigurationValidationException Thrown when the wrapper requires a value and no provider/default value resolves, or when the resolved provider value or default value violates object DataAnnotations or scalar validation rules. Exception Thrown when a concrete scalar validation override throws; override exceptions are not wrapped. Type ConfigAuditReport Describes the resolved configuration state for an AppSurface environment. Remarks Reports are immutable snapshots from the caller\u0027s perspective: provider order, entries, diagnostics, and redaction policy describe one audit run and should not be treated as live configuration. Use Entries for machine inspection and ConfigAuditTextRenderer when operators need a deterministic text dump. Property Environment string Environment { get; init; } Gets the environment this report describes. Property GeneratedAt DateTimeOffset GeneratedAt { get; init; } Gets the time when this report was generated. Property Providers IReadOnlyList\u003CConfigAuditProvider\u003E Providers { get; init; } Gets the provider precedence used while producing this report. Property Entries IReadOnlyList\u003CConfigAuditEntry\u003E Entries { get; init; } Gets the known configuration entries resolved for this environment. Property Diagnostics IReadOnlyList\u003CConfigAuditDiagnostic\u003E Diagnostics { get; init; } Gets report-level diagnostics that are not tied to a single entry. Property Redaction ConfigAuditRedaction Redaction { get; init; } Gets the redaction policy applied before this report was returned. Type ConfigAuditProvider Describes one provider in the audit report precedence list. Remarks Precedence is the display order used by audit reports. Environment providers are marked as overrides because they are checked before normal priority-ordered providers. Property Name string Name { get; init; } Gets the provider name. Property Priority int Priority { get; init; } Gets the provider priority. Property Precedence int Precedence { get; init; } Gets the precedence rank used by the configuration manager. Lower ranks are checked first. Property IsOverride bool IsOverride { get; init; } Gets a value indicating whether the manager treats this provider as an override outside normal priority order. Type ConfigAuditEntry Describes one known configuration entry and its source records. Remarks State summarizes the entry as a whole. Object entries can contain Children with more specific provenance, including nested ConfigAuditEntryState.PartiallyResolved states when descendants are patched. DisplayValue is already redacted and can be null for complex values; callers should inspect children instead of assuming a full object dump is available. Property Key string Key { get; init; } Gets the configuration key. Property DeclaredType string? DeclaredType { get; init; } Gets the declared value type name when known. Property State ConfigAuditEntryState State { get; init; } Gets the resolved entry state. Property DisplayValue string? DisplayValue { get; init; } Gets the display-safe value. Sensitive values are already redacted. Property IsRedacted bool IsRedacted { get; init; } Gets a value indicating whether DisplayValue was redacted. Property Sources IReadOnlyList\u003CConfigAuditSourceRecord\u003E Sources { get; init; } Gets the source records that contributed to this entry. Property Children IReadOnlyList\u003CConfigAuditEntry\u003E Children { get; init; } Gets child entries for object-valued configuration. Property Diagnostics IReadOnlyList\u003CConfigAuditDiagnostic\u003E Diagnostics { get; init; } Gets diagnostics specific to this entry. Type ConfigAuditSourceRecord Describes one source that contributed to a configuration entry. Remarks Source records identify where a value came from and how it was applied. File paths, environment variable names, and config paths are optional because not every provider exposes the same provenance. The source role is especially important for mixed values: a base source can be combined with patch sources from higher-priority providers. Property Kind ConfigAuditSourceKind Kind { get; init; } Gets the source kind. Property ProviderName string? ProviderName { get; init; } Gets the provider name when applicable. Property ProviderPriority int? ProviderPriority { get; init; } Gets the provider priority when applicable. Property FilePath string? FilePath { get; init; } Gets the file path for file-sourced values. Property EnvironmentVariableName string? EnvironmentVariableName { get; init; } Gets the environment variable name for environment-sourced values. Property ConfigPath string? ConfigPath { get; init; } Gets the source config path. Property AppliedToPath string? AppliedToPath { get; init; } Gets the target config path affected by this source. Property Role ConfigAuditSourceRole Role { get; init; } Gets the role this source played in resolution. Property Sensitivity ConfigAuditSensitivity Sensitivity { get; init; } Gets the sensitivity classification supplied by the source. Type ConfigAuditDiagnostic Describes a diagnostic emitted while building a configuration audit report. Remarks Diagnostic messages are intended to be display-safe and stable enough for operators. Use Code for programmatic handling, and use Source when a diagnostic can be tied to one provider, file, or environment variable. Property Severity ConfigAuditDiagnosticSeverity Severity { get; init; } Gets the diagnostic severity. Property Code string Code { get; init; } Gets a stable diagnostic code. Property Message string Message { get; init; } Gets the display-safe diagnostic message. Property Key string? Key { get; init; } Gets the configuration key associated with the diagnostic, when any. Property ConfigPath string? ConfigPath { get; init; } Gets the member/config path associated with the diagnostic, when any. Property Source ConfigAuditSourceRecord? Source { get; init; } Gets the source associated with the diagnostic, when any. Type ConfigAuditRedaction Describes the redaction policy applied to a configuration audit report. Remarks The built-in policy is always enabled and uses fragment matching before values are exposed through ConfigAuditEntry.DisplayValue . MatchedFragments is a snapshot for explanation, not a mutable policy hook. Property Enabled bool Enabled { get; init; } Gets a value indicating whether redaction was enabled. Property MatchedFragments IReadOnlyList\u003Cstring\u003E MatchedFragments { get; init; } Gets the sensitive fragments matched by the built-in redactor. Property Placeholder string Placeholder { get; init; } Gets the display placeholder used for redacted values. Enum ConfigAuditEntryState Identifies the resolution state for an audited configuration entry. Remarks Values are explicit and append-only so serialized reports remain stable across releases. Enum ConfigAuditSourceKind Identifies the kind of configuration source. Remarks Values are explicit and append-only so serialized reports remain stable across releases. Enum ConfigAuditSourceRole Identifies how a source contributed to the final value. Remarks Values are explicit and append-only so serialized reports remain stable across releases. Enum ConfigAuditSensitivity Classifies source or value sensitivity. Remarks Values are explicit and append-only so serialized reports remain stable across releases. Enum ConfigAuditDiagnosticSeverity Identifies diagnostic severity. Remarks Values are explicit and append-only so serialized reports remain stable across releases. Type IConfigManager Defines the central manager for configuration, which aggregates multiple IConfigProvider instances.","snippet":"Type ConfigScalarTypes Provides the canonical scalar-type classification shared by configuration validation paths. Method IsScalar bool IsScalar ( Type type ) Returns whether type is treated as a scalar configuration...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-AppSurfaceConfigModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-AppSurfaceConfigModule","title":"AppSurfaceConfigModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","AppSurfaceConfigModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-AppSurfaceConfigModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-Config-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-Config-1","title":"Config\u003CT\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","Config\u003CT\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-Config-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditDiagnostic","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditDiagnostic","title":"ConfigAuditDiagnostic","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditDiagnostic"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditDiagnostic"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditDiagnosticSeverity","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditDiagnosticSeverity","title":"ConfigAuditDiagnosticSeverity","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditDiagnosticSeverity"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditDiagnosticSeverity"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditEntry","title":"ConfigAuditEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditEntryState","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditEntryState","title":"ConfigAuditEntryState","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditEntryState"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditEntryState"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditKnownEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditKnownEntry","title":"ConfigAuditKnownEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditKnownEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditKnownEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditProvider","title":"ConfigAuditProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditRedaction","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditRedaction","title":"ConfigAuditRedaction","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditRedaction"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditRedaction"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditRedactor","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditRedactor","title":"ConfigAuditRedactor","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditRedactor"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditRedactor"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditReport","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditReport","title":"ConfigAuditReport","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditReport"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditReport"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditReporter","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditReporter","title":"ConfigAuditReporter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditReporter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditReporter"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSensitivity","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSensitivity","title":"ConfigAuditSensitivity","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditSensitivity"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditSensitivity"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditServiceCollectionExtensions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditServiceCollectionExtensions","title":"ConfigAuditServiceCollectionExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditServiceCollectionExtensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditServiceCollectionExtensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSourceKind","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSourceKind","title":"ConfigAuditSourceKind","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditSourceKind"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditSourceKind"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSourceRecord","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSourceRecord","title":"ConfigAuditSourceRecord","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditSourceRecord"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditSourceRecord"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSourceRole","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditSourceRole","title":"ConfigAuditSourceRole","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditSourceRole"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditSourceRole"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditTextRenderer","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigAuditTextRenderer","title":"ConfigAuditTextRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigAuditTextRenderer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigAuditTextRenderer"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigDataAnnotationsValidator","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigDataAnnotationsValidator","title":"ConfigDataAnnotationsValidator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigDataAnnotationsValidator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigDataAnnotationsValidator"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigKeyAttribute","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigKeyAttribute","title":"ConfigKeyAttribute","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigKeyAttribute"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigKeyAttribute"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigKeyRequiredAttribute","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigKeyRequiredAttribute","title":"ConfigKeyRequiredAttribute","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigKeyRequiredAttribute"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigKeyRequiredAttribute"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigPatchDiagnosticResult","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigPatchDiagnosticResult","title":"ConfigPatchDiagnosticResult","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigPatchDiagnosticResult"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigPatchDiagnosticResult"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigPresenceValidator","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigPresenceValidator","title":"ConfigPresenceValidator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigPresenceValidator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigPresenceValidator"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigScalarTypes","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigScalarTypes","title":"ConfigScalarTypes","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigScalarTypes"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigScalarTypes"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigStruct-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigStruct-1","title":"ConfigStruct\u003CT\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigStruct\u003CT\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigStruct-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigurationValidationException","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigurationValidationException","title":"ConfigurationValidationException","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigurationValidationException"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigurationValidationException"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigurationValidationFailure","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigurationValidationFailure","title":"ConfigurationValidationFailure","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigurationValidationFailure"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigurationValidationFailure"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValidationFailureFactory","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValidationFailureFactory","title":"ConfigValidationFailureFactory","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigValidationFailureFactory"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigValidationFailureFactory"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueMinLengthAttribute","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueMinLengthAttribute","title":"ConfigValueMinLengthAttribute","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigValueMinLengthAttribute"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigValueMinLengthAttribute"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueNotEmptyAttribute","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueNotEmptyAttribute","title":"ConfigValueNotEmptyAttribute","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigValueNotEmptyAttribute"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigValueNotEmptyAttribute"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueRangeAttribute","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueRangeAttribute","title":"ConfigValueRangeAttribute","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigValueRangeAttribute"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigValueRangeAttribute"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueResolution","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueResolution","title":"ConfigValueResolution","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigValueResolution"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigValueResolution"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueValidationAttribute","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigValueValidationAttribute","title":"ConfigValueValidationAttribute","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigValueValidationAttribute"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigValueValidationAttribute"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigWrapperInspection","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-ConfigWrapperInspection","title":"ConfigWrapperInspection","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","ConfigWrapperInspection"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-ConfigWrapperInspection"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-DefaultConfigFileLocationProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-DefaultConfigFileLocationProvider","title":"DefaultConfigFileLocationProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","DefaultConfigFileLocationProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-DefaultConfigFileLocationProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-DefaultConfigManager","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-DefaultConfigManager","title":"DefaultConfigManager","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","DefaultConfigManager"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-DefaultConfigManager"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-EnvironmentConfigProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-EnvironmentConfigProvider","title":"EnvironmentConfigProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","EnvironmentConfigProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-EnvironmentConfigProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-FileBasedConfigProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-FileBasedConfigProvider","title":"FileBasedConfigProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","FileBasedConfigProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-FileBasedConfigProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfig","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfig","title":"IConfig","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfig"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfig"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigAuditReporter","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigAuditReporter","title":"IConfigAuditReporter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigAuditReporter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigAuditReporter"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigDiagnosticPatcher","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigDiagnosticPatcher","title":"IConfigDiagnosticPatcher","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigDiagnosticPatcher"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigDiagnosticPatcher"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigDiagnosticProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigDiagnosticProvider","title":"IConfigDiagnosticProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigDiagnosticProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigDiagnosticProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigFileLocationProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigFileLocationProvider","title":"IConfigFileLocationProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigFileLocationProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigFileLocationProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigInspectable","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigInspectable","title":"IConfigInspectable","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigInspectable"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigInspectable"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigManager","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigManager","title":"IConfigManager","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigManager"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigManager"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigProvider","title":"IConfigProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigValuePatcher","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IConfigValuePatcher","title":"IConfigValuePatcher","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IConfigValuePatcher"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IConfigValuePatcher"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IEnvironmentConfigProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-IEnvironmentConfigProvider","title":"IEnvironmentConfigProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","IEnvironmentConfigProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-IEnvironmentConfigProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-RedactedValue","path":"/docs/Namespaces/ForgeTrust.AppSurface.Config.html#ForgeTrust-AppSurface-Config-RedactedValue","title":"RedactedValue","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Config","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Config","RedactedValue"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Config#ForgeTrust-AppSurface-Config-RedactedValue"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html","title":"Console","summary":"Type ConsoleOptions Represents configurable startup options for AppSurface console applications. Property Default ConsoleOptions Default { get; } Gets a default instance of ConsoleOptions . Property OutputMode...","headings":["ConsoleOptions","Default","OutputMode","CustomRegistrations","CommandService","CheckForUnknownOptions","IOptionSuggester","GetSuggestions","ConsoleStartup\u003CTModule\u003E","WithOptions","RunAsync","ConfigureAdditionalServices","ConsoleApp\u003CTStartup, TModule\u003E","ConsoleApp\u003CTModule\u003E","ChainedCommand","Configure","CommandChainBuilder","Add","AddIf","LevenshteinOptionSuggester","ComputeLevenshteinDistance"],"bodyText":"Type ConsoleOptions Represents configurable startup options for AppSurface console applications. Property Default ConsoleOptions Default { get; } Gets a default instance of ConsoleOptions . Property OutputMode ConsoleOutputMode OutputMode { get; set; } Gets or sets how the console app should balance command-owned output against ambient host lifecycle diagnostics. Remarks The default value is ConsoleOutputMode.Default , which preserves the standard Generic Host behavior. Set this to ConsoleOutputMode.CommandFirst for public CLI tools whose help, validation, and progress output should stay command-centric. Property CustomRegistrations List\u003CAction\u003CIServiceCollection\u003E\u003E CustomRegistrations { get; } Gets custom service registrations that should be applied after AppSurface\u0027s built-in console services. Remarks Use this for advanced console hosting scenarios, such as injecting a custom CliFx.Infrastructure.IConsole implementation or additional logging providers for tests and embedded hosts. Type CommandService Method CheckForUnknownOptions void CheckForUnknownOptions ( IConsole console ) Analyzes the current command-line arguments to detect unknown or mistyped options after a command has failed and, when possible, displays suggestions for valid alternatives. Parameters console The console used to write diagnostic messages and option suggestions to the user. Remarks This method performs three main steps: Resolves the target command type from the parsed arguments and registered commands. Extracts the set of valid option names for the resolved command. Compares the provided arguments against the valid options and uses IOptionSuggester to present suggestions for any unknown options. Type IOptionSuggester Defines a contract for suggesting alternative options when an unknown option is provided. Remarks Use this abstraction when command parsing should improve interactive UX for unpredictable user-typed options or dynamic option sets without coupling callers to a specific matching algorithm. Prefer direct parser validation, explicit enum checks, or fixed lookup errors for tiny static option sets and strict non-interactive flows where suggestions add noise instead of recovery value. Method GetSuggestions IReadOnlyList\u003Cstring\u003E GetSuggestions ( string? unknownOption , IEnumerable\u003Cstring\u003E? validOptions ) Gets a list of suggested options based on the unknown option and the list of valid options. Parameters unknownOption The unknown option provided by the user, or null when parsing did not identify one. validOptions The valid options for the current command, or null when none are available. Returns A non-null collection of suggested options. Remarks GetSuggestions implementations should treat a null or empty unknownOption , or a null or empty validOptions sequence, as producing no suggestions. The returned IReadOnlyList{T} must be non-null, should not contain duplicates, and should be deterministic: relevance-first when a scorer exists, then alphabetical for ties. Use this method for recovery hints, not as the source of truth for whether an option is valid. Type ConsoleStartup\u003CTModule\u003E A base class for console application startup logic, extending the module-based initialization. Type Parameters TModule The type of the root module. Method WithOptions ConsoleStartup\u003CTModule\u003E WithOptions ( Action\u003CConsoleOptions\u003E? configureOptions = null ) Registers an optional callback to customize ConsoleOptions and enables fluent chaining. Parameters configureOptions An optional action invoked before startup context creation to modify console startup behavior. Returns The same ConsoleStartup{TModule} instance to support fluent configuration. Method RunAsync Task RunAsync ( string[] args ) Runs the console application asynchronously using a startup context derived from the supplied arguments and configured console options. Parameters args Command-line arguments supplied to the console application. Returns A task that completes when the host run finishes. Method ConfigureAdditionalServices void ConfigureAdditionalServices ( StartupContext context , IServiceCollection services ) Allows derived classes to register additional services. Parameters context The startup context. services The service collection. Type ConsoleApp\u003CTStartup, TModule\u003E This class is used to run a console application with a specified startup class and module. This allows for further customization of the consoles startup process. Method RunAsync Task RunAsync ( string[] args , Action\u003CConsoleOptions\u003E? configureOptions = null ) Runs the console application asynchronously using a custom startup class. Parameters args Command-line arguments. configureOptions An optional delegate to customize ConsoleOptions before startup. Returns A task representing the run operation. Type ConsoleApp\u003CTModule\u003E This class is used to run a console application with a specified module and a generic startup. Type Parameters TModule The type of the root module. Method RunAsync Task RunAsync ( string[] args , Action\u003CConsoleOptions\u003E? configureOptions = null ) Runs the console application asynchronously with a generic startup. Parameters args Command-line arguments. configureOptions An optional delegate to customize ConsoleOptions before startup. Returns A task representing the run operation. Type ChainedCommand A command that can execute a sequence of other commands. Parameters and options defined on the parent command are automatically forwarded to the child commands when they share the same property name. Required parameters of child commands are validated before any command in the chain is executed. Method Configure void Configure ( CommandChainBuilder builder ) Configures the sequence of commands to execute. Parameters builder Fluent builder to define the chain. Type CommandChainBuilder Fluent builder used to configure the chain of commands. Method Add CommandChainBuilder Add \u003CTCommand\u003E () Adds a command to the execution chain. Method AddIf CommandChainBuilder AddIf \u003CTCommand\u003E ( Func\u003Cbool\u003E condition ) Adds a command to the chain that will execute only when condition returns true. Type LevenshteinOptionSuggester Suggests options using the Levenshtein distance algorithm. Method GetSuggestions IReadOnlyList\u003Cstring\u003E GetSuggestions ( string? unknownOption , IEnumerable\u003Cstring\u003E? validOptions ) Gets a list of suggested options based on their Levenshtein distance to the unknown option. Parameters unknownOption The unknown command line option. validOptions The list of valid command line options. Returns A collection of suggested options that closely match the unknown option. Method ComputeLevenshteinDistance int ComputeLevenshteinDistance ( string s , string t ) Computes the Levenshtein distance between two strings using a dynamic programming approach. Parameters s The first string to compare. t The second string to compare. Returns The number of single-character edits (insertions, deletions, or substitutions) required to change one string into the other.","snippet":"Type ConsoleOptions Represents configurable startup options for AppSurface console applications. Property Default ConsoleOptions Default { get; } Gets a default instance of ConsoleOptions . Property OutputMode...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ChainedCommand","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ChainedCommand","title":"ChainedCommand","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","ChainedCommand"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-ChainedCommand"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ChainedCommand-CommandChainBuilder","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ChainedCommand-CommandChainBuilder","title":"CommandChainBuilder","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","CommandChainBuilder"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-ChainedCommand-CommandChainBuilder"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-CommandService","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-CommandService","title":"CommandService","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","CommandService"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-CommandService"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleApp-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleApp-1","title":"ConsoleApp\u003CTModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","ConsoleApp\u003CTModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-ConsoleApp-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleApp-2","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleApp-2","title":"ConsoleApp\u003CTStartup, TModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","ConsoleApp\u003CTStartup, TModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-ConsoleApp-2"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleOptions","title":"ConsoleOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","ConsoleOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-ConsoleOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleStartup-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-ConsoleStartup-1","title":"ConsoleStartup\u003CTModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","ConsoleStartup\u003CTModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-ConsoleStartup-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-IOptionSuggester","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-IOptionSuggester","title":"IOptionSuggester","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","IOptionSuggester"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-IOptionSuggester"},{"id":"Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-LevenshteinOptionSuggester","path":"/docs/Namespaces/ForgeTrust.AppSurface.Console.html#ForgeTrust-AppSurface-Console-LevenshteinOptionSuggester","title":"LevenshteinOptionSuggester","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Console","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Console","LevenshteinOptionSuggester"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Console#ForgeTrust-AppSurface-Console-LevenshteinOptionSuggester"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.Defaults.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.Defaults.html","title":"Defaults","summary":"Type NoHostModule A basic implementation of IAppSurfaceHostModule that does nothing. This is useful for providing implementations of apps that do not require a module. Remarks Use NoHostModule only when no part of the...","headings":["NoHostModule","ConfigureServices","RegisterDependentModules","ConfigureHostBeforeServices","ConfigureHostAfterServices","InternalServicesModule","DefaultEnvironmentProvider","GetEnvironmentVariable","Environment","IsDevelopment"],"bodyText":"Type NoHostModule A basic implementation of IAppSurfaceHostModule that does nothing. This is useful for providing implementations of apps that do not require a module. Remarks Use NoHostModule only when no part of the application expects module-provided services, dependency registrations, middleware, endpoints, or host configuration. It is safe for minimal hosts that rely entirely on framework defaults. Create a real IAppSurfaceHostModule when the app needs service registration, dependency wiring, or host lifecycle hooks. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Configures services for the module. This implementation is empty. Parameters context The startup context. services The service collection. Remarks No services are added. Callers that expect module-owned services must not use NoHostModule . Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers dependent modules. This implementation is empty. Parameters builder The module dependency builder. Remarks No dependencies are declared. Create a concrete module when startup ordering or dependency modules matter. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , IHostBuilder builder ) Configures the host before services are registered. This implementation is empty. Parameters context The startup context. builder The host builder. Remarks No host configuration is applied before service registration. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , IHostBuilder builder ) Configures the host after services are registered. This implementation is empty. Parameters context The startup context. builder The host builder. Remarks No host configuration is applied after service registration. Type InternalServicesModule Internal Services Registration Type DefaultEnvironmentProvider Default implementation of IEnvironmentProvider that retrieves the environment from system environment variables. It checks for \u0022ASPNETCORE_ENVIRONMENT\u0022 first, then \u0022DOTNET_ENVIRONMENT\u0022, and defaults to \u0022Production\u0022 if neither is set. Can be overridden by passing a custom implementation to the StartupContext , when building the host. Method GetEnvironmentVariable string? GetEnvironmentVariable ( string name , string? defaultValue = null ) Gets the value of an environment variable from the system. Parameters name The exact environment variable name to query. defaultValue The default value to return if the environment variable is unset. Returns The environment variable value, an empty string when explicitly set empty, or the provided default if the variable is unset. Remarks Use GetEnvironmentVariable when callers need the provider\u0027s centralized lookup and unset-value defaulting behavior. Use Environment or IsDevelopment for the active application environment, and prefer direct System.Environment access only for low-level infrastructure code. Passing a null or empty name follows System.Environment.GetEnvironmentVariable(string) semantics. Do not log returned values unless the variable is known to be non-sensitive, and do not trim or alter casing unless the caller intentionally wants to change the platform-specific value. Property Environment string Environment { get; } The current environment name. Read from \u0022ASPNETCORE_ENVIRONMENT\u0022 or \u0022DOTNET_ENVIRONMENT\u0022 environment variables, defaults to \u0022Production\u0022 if neither is set. Property IsDevelopment bool IsDevelopment { get; } True if the current environment is \u0022Development\u0022.","snippet":"Type NoHostModule A basic implementation of IAppSurfaceHostModule that does nothing. This is useful for providing implementations of apps that do not require a module. Remarks Use NoHostModule only when no part of the...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","Defaults"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core.Defaults"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.Defaults.html#ForgeTrust-AppSurface-Core-Defaults-DefaultEnvironmentProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.Defaults.html#ForgeTrust-AppSurface-Core-Defaults-DefaultEnvironmentProvider","title":"DefaultEnvironmentProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","Defaults","DefaultEnvironmentProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core.Defaults#ForgeTrust-AppSurface-Core-Defaults-DefaultEnvironmentProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.Defaults.html#ForgeTrust-AppSurface-Core-Defaults-InternalServicesModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.Defaults.html#ForgeTrust-AppSurface-Core-Defaults-InternalServicesModule","title":"InternalServicesModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","Defaults","InternalServicesModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core.Defaults#ForgeTrust-AppSurface-Core-Defaults-InternalServicesModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.Defaults.html#ForgeTrust-AppSurface-Core-Defaults-NoHostModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.Defaults.html#ForgeTrust-AppSurface-Core-Defaults-NoHostModule","title":"NoHostModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","Defaults","NoHostModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core.Defaults#ForgeTrust-AppSurface-Core-Defaults-NoHostModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.Extensions.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.Extensions.html","title":"Extensions","summary":"Type EnumerableExtensions Provides extension methods for IEnumerable{T} to perform parallel operations. Method ParallelSelectAsync 3 overloads Task\u003CIEnumerable\u003CTResult\u003E\u003E ParallelSelectAsync \u003CTSource, TResult\u003E ( this...","headings":["EnumerableExtensions","ParallelSelectAsync","ParallelSelectAsyncEnumerable","StringExtensions","SplitOnWhiteSpace"],"bodyText":"Type EnumerableExtensions Provides extension methods for IEnumerable{T} to perform parallel operations. Method ParallelSelectAsync 3 overloads Task\u003CIEnumerable\u003CTResult\u003E\u003E ParallelSelectAsync \u003CTSource, TResult\u003E ( this IEnumerable\u003CTSource\u003E source , Func\u003CTSource, CancellationToken, Task\u003CTResult\u003E\u003E body , int maxDegreeOfParallelism , CancellationToken cancellationToken = default ) Projects each element of a sequence into a new form with bounded concurrency and preserves the input order of results. Parameters source The sequence of input items. body An asynchronous transform that receives an input item and a cancellation token and produces a result. maxDegreeOfParallelism The maximum number of concurrent invocations of body ; must be greater than zero. cancellationToken A token to observe while waiting for tasks to complete. Returns An IEnumerable{T} of results in the same order as the input sequence. Exceptions ArgumentNullException Thrown when source or body is null. ArgumentOutOfRangeException Thrown when maxDegreeOfParallelism is less than or equal to zero. OperationCanceledException The operation was canceled via cancellationToken . Remarks Exceptions thrown by the body function propagate to the returned task. Task\u003CIEnumerable\u003CTResult\u003E\u003E ParallelSelectAsync \u003CTSource, TResult\u003E ( this IEnumerable\u003CTSource\u003E source , Func\u003CTSource, CancellationToken, Task\u003CTResult\u003E\u003E body , int maxDegreeOfParallelism , CancellationToken cancellationToken , ILogger logger ) Projects each element of a sequence into a new form with bounded concurrency, preserves the input order of results, observes cancellationToken , and logs suppressed cleanup diagnostics through logger . Parameters source The sequence of input items. body An asynchronous transform that receives an input item and a cancellation token and produces a result. maxDegreeOfParallelism The maximum number of concurrent invocations of body ; must be greater than zero. cancellationToken A token to observe while waiting for tasks to complete. logger Logger for cleanup diagnostics that would otherwise be suppressed to preserve the primary exception. Returns An IEnumerable{T} of results in the same order as the input sequence. Exceptions ArgumentNullException Thrown when source , body , or logger is null. ArgumentOutOfRangeException Thrown when maxDegreeOfParallelism is less than or equal to zero. OperationCanceledException The operation was canceled via cancellationToken . Remarks Exceptions thrown by the body function propagate to the returned task. IAsyncEnumerable\u003CTResult\u003E ParallelSelectAsync \u003CTSource, TResult\u003E ( this IEnumerable\u003CTSource\u003E source , Func\u003CTSource, Task\u003CTResult\u003E\u003E body , int maxDegreeOfParallelism , CancellationToken cancellationToken = default ) Produces an async sequence of results projected from each element of source , yielding results in the original input order while limiting concurrent selector executions. Parameters source The input sequence to project. body A selector that produces a Task{TResult} for an input element; this selector does not receive or observe the supplied cancellationToken . maxDegreeOfParallelism The maximum number of selector tasks allowed to run concurrently; must be greater than zero. cancellationToken A token to observe for request to cancel the overall enumeration. Returns The sequence of transformed elements in the original input order; concurrency is limited to maxDegreeOfParallelism . Method ParallelSelectAsyncEnumerable 3 overloads IAsyncEnumerable\u003CTResult\u003E ParallelSelectAsyncEnumerable \u003CTSource, TResult\u003E ( this IEnumerable\u003CTSource\u003E source , Func\u003CTSource, CancellationToken, Task\u003CTResult\u003E\u003E body , int maxDegreeOfParallelism , int bufferMultiplier = 4 , CancellationToken cancellationToken = default ) Produces an asynchronous sequence of results by applying body to each element of source , limiting concurrency to maxDegreeOfParallelism and preserving the input order. The internal channel capacity is capped at maxDegreeOfParallelism * bufferMultiplier . Parameters source The input sequence to project; must not be null. body A selector that projects an element to a Task{TResult} ; it receives the element and a CancellationToken that is signaled when the operation is canceled. maxDegreeOfParallelism The maximum number of selector tasks that may run concurrently; must be greater than zero. bufferMultiplier A multiplier used to compute the internal channel capacity as maxDegreeOfParallelism * bufferMultiplier (capped to int.MaxValue ); must be at least 1. cancellationToken Token to observe for cooperative cancellation of the overall operation. Returns An IAsyncEnumerable{TResult} that yields projected results in the same order as the source sequence. Exceptions ArgumentNullException Thrown if source or body is null. ArgumentOutOfRangeException Thrown if maxDegreeOfParallelism is less than or equal to zero or if bufferMultiplier is less than 1. IAsyncEnumerable\u003CTResult\u003E ParallelSelectAsyncEnumerable \u003CTSource, TResult\u003E ( this IEnumerable\u003CTSource\u003E source , Func\u003CTSource, CancellationToken, Task\u003CTResult\u003E\u003E body , int maxDegreeOfParallelism , int bufferMultiplier , CancellationToken cancellationToken , ILogger logger ) Produces an asynchronous sequence of results by applying body to each element of source , limiting concurrency, preserving input order, observing cancellationToken , and logging suppressed cleanup diagnostics through logger . Parameters source The input sequence to project; must not be null. body A selector that projects an element to a Task{TResult} ; it receives the element and a cancellation token that is signaled when the operation is canceled. maxDegreeOfParallelism The maximum number of selector tasks that may run concurrently; must be greater than zero. bufferMultiplier A multiplier used to compute the internal channel capacity as maxDegreeOfParallelism * bufferMultiplier (capped to int.MaxValue ); must be at least 1. cancellationToken Token to observe for cooperative cancellation of the overall operation. logger Logger for cleanup diagnostics that would otherwise be suppressed to preserve the primary exception. Returns An IAsyncEnumerable{TResult} that yields projected results in the same order as the source sequence. Exceptions ArgumentNullException Thrown if source , body , or logger is null. ArgumentOutOfRangeException Thrown if maxDegreeOfParallelism is less than or equal to zero or if bufferMultiplier is less than 1. IAsyncEnumerable\u003CTResult\u003E ParallelSelectAsyncEnumerable \u003CTSource, TResult\u003E ( this IEnumerable\u003CTSource\u003E source , Func\u003CTSource, Task\u003CTResult\u003E\u003E body , int maxDegreeOfParallelism , int bufferMultiplier = 4 , CancellationToken cancellationToken = default ) Projects each element of source using the provided task-returning selector with bounded concurrency and yields the results in the same order as the source. Parameters source The input sequence to project. body A selector that produces a Task{TResult} for an input element. This overload does not pass or observe a CancellationToken to the selector. maxDegreeOfParallelism The maximum number of selector tasks allowed to run concurrently; must be greater than zero. bufferMultiplier Multiplier applied to maxDegreeOfParallelism to determine internal channel capacity; must be at least 1. cancellationToken Token to cancel iteration and background work. Returns An IAsyncEnumerable{TResult} that yields projected results in the input order. Exceptions ArgumentNullException source or body is null. ArgumentOutOfRangeException maxDegreeOfParallelism is less than or equal to 0, or bufferMultiplier is less than 1. Type StringExtensions Provides extension methods for strings. Method SplitOnWhiteSpace string[] SplitOnWhiteSpace ( this string? input ) Splits a string on any whitespace character, removing empty entries. Parameters input The string to split. Returns An array of substrings delimited by whitespace.","snippet":"Type EnumerableExtensions Provides extension methods for IEnumerable{T} to perform parallel operations. Method ParallelSelectAsync 3 overloads Task\u003CIEnumerable\u003CTResult\u003E\u003E ParallelSelectAsync \u003CTSource, TResult\u003E ( this...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","Extensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core.Extensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.Extensions.html#ForgeTrust-AppSurface-Core-Extensions-EnumerableExtensions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.Extensions.html#ForgeTrust-AppSurface-Core-Extensions-EnumerableExtensions","title":"EnumerableExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","Extensions","EnumerableExtensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core.Extensions#ForgeTrust-AppSurface-Core-Extensions-EnumerableExtensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.Extensions.html#ForgeTrust-AppSurface-Core-Extensions-StringExtensions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.Extensions.html#ForgeTrust-AppSurface-Core-Extensions-StringExtensions","title":"StringExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","Extensions","StringExtensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core.Extensions#ForgeTrust-AppSurface-Core-Extensions-StringExtensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html","title":"Core","summary":"Namespaces Defaults Extensions Type StartupContext Provides context and configuration during the application startup process. Parameters Args Command-line arguments provided to the application. RootModule The root...","headings":["StartupContext","GetDependencies","DependenciesRegistered","OverrideEntryPointAssembly","ConsoleOutputMode","RootModuleAssembly","EntryPointAssembly","HostIdentityAssembly","EnvironmentProvider","IsDevelopment","ApplicationName","HostApplicationName","PathUtils","FindRepositoryRoot","GetExistingFileDirectory","IAppSurfaceHostModule","ConfigureHostBeforeServices","ConfigureHostAfterServices","CriticalService","RunAsync","LogInitialize","LogStopping","LogException","IEnvironmentProvider"],"bodyText":"Namespaces Defaults Extensions Type StartupContext Provides context and configuration during the application startup process. Parameters Args Command-line arguments provided to the application. RootModule The root module of the application. ApplicationName Optional user-facing display label for product surfaces. Defaults to the root module assembly name when not provided. This value does not control Generic Host/static web asset manifest identity. EnvironmentProvider Optional provider for environment information. CustomRegistrations Optional custom service registrations. Method GetDependencies IReadOnlyList\u003CIAppSurfaceModule\u003E GetDependencies () Gets the list of modules that the application depends on. Returns A read-only list of dependent modules. Property DependenciesRegistered bool DependenciesRegistered { get; set; } Gets or sets whether startup dependency registration has already run for this context. Remarks Defaults to false . AppSurfaceStartup{TRootModule} sets this to true after framework and root-module dependencies are registered so repeated startup-time calls are no-ops for the same StartupContext . This state is intended for single-threaded startup composition and is not safe for concurrent writes. Property OverrideEntryPointAssembly Assembly? OverrideEntryPointAssembly { get; set; } Gets or sets an assembly that should override both application discovery and host manifest identity. Remarks Set this when a test or custom host needs AppSurface to scan a different assembly for commands, MVC parts, or Aspire components, or when static web asset manifest identity must be pinned to a specific assembly. Property ConsoleOutputMode ConsoleOutputMode ConsoleOutputMode { get; set; } Gets or sets how console-oriented apps should present command output relative to ambient host lifecycle diagnostics. Remarks The default value is ConsoleOutputMode.Default , which preserves the standard Generic Host behavior. Console startups can switch to ConsoleOutputMode.CommandFirst when command output should remain the primary user-facing console experience. Non-console apps can ignore this setting. Property RootModuleAssembly Assembly RootModuleAssembly { get; } Gets the assembly that contains the root module. Property EntryPointAssembly Assembly EntryPointAssembly { get; } Gets the assembly used for application-owned type discovery. Remarks AppSurface uses this assembly to discover application-owned commands, MVC application parts, Aspire components, and similar extensibility hooks. By default it stays aligned with the root module assembly so cross-assembly test runners and shared hosts do not accidentally scan the outer process entry assembly. Set OverrideEntryPointAssembly when a host intentionally wants discovery to come from a different assembly. Property HostIdentityAssembly Assembly HostIdentityAssembly { get; } Gets the assembly whose name should be written into the Generic Host environment. Remarks ASP.NET static web assets resolve runtime manifests through Microsoft.Extensions.Hosting.IHostEnvironment.ApplicationName . When OverrideEntryPointAssembly is not provided, AppSurface falls back to Assembly.GetEntryAssembly() here so the host environment tracks the real executable surface rather than the root module\u0027s assembly. When no process entry assembly is available, the root module assembly remains the defensive fallback. Property EnvironmentProvider IEnvironmentProvider EnvironmentProvider { get; } Gets the environment provider for the application. Property IsDevelopment bool IsDevelopment { get; } Gets a value indicating whether the current environment is development. Property ApplicationName string ApplicationName { get; init; } Gets the user-facing name of the application. Remarks This value is intended for product surfaces such as generated OpenAPI titles, command output, and other places where callers need a readable application label. It is intentionally separate from HostApplicationName , which must stay aligned with the assembly identity used by the .NET Generic Host and ASP.NET static web asset manifest discovery. Property HostApplicationName string HostApplicationName { get; } Gets the assembly-backed application identity assigned to Microsoft.Extensions.Hosting.IHostEnvironment.ApplicationName . Remarks ASP.NET static web assets resolve runtime manifests by host application name. Custom display names should not be written into the host environment because they can point static web asset discovery at a non-existent manifest. By default AppSurface uses the process entry assembly when one is available; override OverrideEntryPointAssembly when a test or custom host needs to select a different manifest identity. This host identity is intentionally separate from EntryPointAssembly , which still drives application-owned type discovery. Enum ConsoleOutputMode Describes how AppSurface console apps should balance command-owned output against ambient host lifecycle diagnostics. Type PathUtils Provides utility methods for operations on file and directory paths. Method FindRepositoryRoot 2 overloads string FindRepositoryRoot ( string startPath ) Locates the nearest ancestor directory (starting at startPath ) that contains a \u0060.git\u0060 directory or file, effectively identifying the repository root. Parameters startPath The path from which to begin searching upward for a repository root; may refer to a file or directory. Returns The full path of the nearest ancestor directory containing a \u0060.git\u0060 directory or file, or the original startPath if none is found. Exceptions ArgumentException Thrown when startPath is null, empty, or consists only of whitespace. string FindRepositoryRoot ( string startPath , ILogger logger ) Locates the nearest ancestor directory (starting at startPath ) that contains a \u0060.git\u0060 directory or file, effectively identifying the repository root. Parameters startPath The path from which to begin searching upward for a repository root; may refer to a file or directory. logger Logger for diagnostic warnings when repository-root discovery has to recover from a path that does not exist. Returns The full path of the nearest ancestor directory containing a \u0060.git\u0060 directory or file, or the original startPath if none is found. Exceptions ArgumentException Thrown when startPath is null, empty, or consists only of whitespace. ArgumentNullException Thrown when logger is null. Method GetExistingFileDirectory string GetExistingFileDirectory ( string startPath ) Resolves the containing directory for an existing file path used by repository-root discovery. Parameters startPath A non-empty path already known to reference an existing file. Returns The normalized containing directory for startPath . Exceptions ArgumentException Thrown when the normalized file path does not yield a containing directory. Remarks FindRepositoryRootCore calls GetExistingFileDirectory only after File.Exists(string?) has accepted startPath as an existing file. The method normalizes the value with Path.GetFullPath(string) so relative file paths are canonicalized before returning the directory portion from Path.GetDirectoryName(string?) . If normalization cannot produce a containing directory, ArgumentException.ThrowIfNullOrEmpty(string?, string?) throws to surface the broken existing-file invariant instead of silently probing from an unrelated fallback path. Type IAppSurfaceHostModule Defines a module that can specifically configure the IHostBuilder before and after service registration. Only the root module of an application (or explicitly marked host modules) usually implements this. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , IHostBuilder builder ) Configures the IHostBuilder before any modules have their services configured. Parameters context The context for the current startup process. builder The host builder to configure. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , IHostBuilder builder ) Configures the IHostBuilder after all modules have their services configured. Parameters context The context for the current startup process. builder The host builder to configure. Type CriticalService A base class for background services that are critical to the application\u0027s operation. If a critical service fails or exits, the entire application will be shut down. Method RunAsync Task RunAsync ( CancellationToken stoppingToken ) Implements the core logic of the critical service. Parameters stoppingToken A token that is signaled when the service should stop. Returns A task that represents the service\u0027s execution. Method LogInitialize void LogInitialize ( string serviceType ) Logs that the critical service is initializing. Parameters serviceType The name of the service type. Method LogStopping void LogStopping ( string serviceType ) Logs that the critical service is stopping. Parameters serviceType The name of the service type. Method LogException void LogException ( Exception exception , string serviceType ) Logs an unhandled exception that occurred in the critical service. Parameters exception The unhandled exception. serviceType The name of the service type. Type IEnvironmentProvider Provides information about the application\u0027s environment and configuration variables. Remarks Use IEnvironmentProvider for DI-friendly, testable environment access in application and core code. Prefer direct System.Environment access only in infrastructure adapters, one-off scripts, or the implementation of this contract. IsDevelopment must stay consistent with Environment and should be derived by comparing the environment name to Development with ordinal ignore-case semantics. GetEnvironmentVariable implementations should be side-effect-free, preserve OS-specific variable name behavior, and document invalid-name handling when they do not delegate directly to System.Environment . Method GetEnvironmentVariable string? GetEnvironmentVariable ( string name , string? defaultValue = null ) Gets the value of an environment variable. Parameters name The exact environment variable name to query. defaultValue The value to return when the variable is unset. Returns The variable value, an empty string when explicitly set empty, or defaultValue when unset. Remarks Implementations should be side-effect-free and preserve the platform\u0027s environment-name behavior: Windows is generally case-insensitive, while Unix-like systems are case-sensitive. Return defaultValue only when the variable is unset and the underlying lookup returns null ; an explicitly empty variable is a real empty string and should not be replaced by the default. Property Environment string Environment { get; } Gets the current environment name (e.g., \u0022Development\u0022, \u0022Staging\u0022, \u0022Production\u0022). Property IsDevelopment bool IsDevelopment { get; } Gets a value indicating whether the current environment is \u0022Development\u0022. Type ModuleDependencyBuilder A builder used to discover and register module dependencies recursively. Remarks ModuleDependencyBuilder is intended for the single-threaded startup composition phase. It is not thread-safe; callers must synchronize access if multiple threads could call AddModule{T} or enumerate Modules concurrently. Method AddModule ModuleDependencyBuilder AddModule \u003CT\u003E () Adds a module of type T and its dependencies to the builder. Type Parameters T The module type to add. It must have a public parameterless constructor. Returns The current ModuleDependencyBuilder instance. Remarks The module instance is created with the new() constraint and pre-registered before IAppSurfaceModule.RegisterDependentModules(ModuleDependencyBuilder) runs. That pre-registration prevents infinite recursion for cyclic module graphs and means dependency callbacks observe already-created module instances. Prefer manual registration or a factory-based composition root when module construction needs dependency injection, runtime arguments, or externally owned disposable resources. If dependency registration throws, the newly created module remains in the builder, so later AddModule{T} calls for that same type are no-ops against a partial graph. Treat registration failures as fatal for the current builder instance. Property Modules IEnumerable\u003CIAppSurfaceModule\u003E Modules { get; } Gets the collection of registered modules. Remarks Modules are keyed by concrete type and added once. Enumeration order is implementation-dependent and should not be treated as a stable contract. A module is visible in Modules before its IAppSurfaceModule.RegisterDependentModules(ModuleDependencyBuilder) callback registers children. Type IAppSurfaceStartup Defines the entry point for starting and running an AppSurface application. Remarks IAppSurfaceStartup.CreateHostBuilder is called before IAppSurfaceStartup.RunAsync . The implementation configures an IHostBuilder , but the framework or caller owns starting, stopping, and disposing the built IHost . CreateHostBuilder must not start the host or perform blocking I/O and should be idempotent unless documented otherwise. RunAsync may be called once per StartupContext , should remain asynchronous, and should honor cancellation exposed by the configured host. Method CreateHostBuilder IHostBuilder CreateHostBuilder ( StartupContext context ) Creates and configures the IHostBuilder for the application. Parameters context The startup context containing configuration and arguments. Returns A configured host builder. Method RunAsync Task RunAsync ( StartupContext context ) Runs the application asynchronously using the provided startup context. Parameters context The startup context for the application. Returns A task that represents the asynchronous run operation. Type AppSurfaceStartup Provides a base implementation for starting and running applications with module support. Remarks Inherit from AppSurfaceStartup{TRootModule} when the application has a concrete root IAppSurfaceHostModule and can use the standard AppSurface host-building flow. Use a host-specific startup such as WebStartup when middleware or endpoint hooks are needed, or implement IAppSurfaceStartup directly when the host lifecycle is custom. StartupContext.ApplicationName is the AppSurface-facing label used by modules and diagnostics; StartupContext.HostApplicationName is the generic host identity applied to configuration and hosting infrastructure. Method GetStartupLogger ILogger GetStartupLogger () Provides an ILogger named after the concrete startup type. Returns An ILogger whose category name is the concrete startup type\u0027s name. Type AppSurfaceStartup\u003CTRootModule\u003E An abstract base class for initializing an AppSurface application with a specific root module. Type Parameters TRootModule The type of the root module for the application. Remarks AppSurfaceStartup{TRootModule} creates TRootModule through the new() constraint, discovers its dependencies, and lets only IAppSurfaceHostModule dependencies receive host lifecycle hooks. Plain IAppSurfaceModule dependencies participate in service registration only. Prefer this base class for console or generic-host apps; use web-specific startup types for ASP.NET Core pipeline work. Method RunAsync 3 overloads Task IAppSurfaceStartup. RunAsync ( StartupContext context ) Runs the startup sequence using the provided startup context. Parameters context Startup configuration including application arguments, root module, and dependency/module registrations. Returns A task that completes when the startup sequence finishes. Task RunAsync ( string[] args ) Starts the application\u0027s run sequence using the specified command-line arguments. Parameters args Command-line arguments supplied to the application. Returns A task that completes when the host run finishes. Task RunAsync ( StartupContext context ) Runs the host configured by the provided startup context and logs lifecycle events according to the configured console output mode. Parameters context Context containing application name, root module, dependencies, and any custom registrations used to build and configure the host. Returns A task that completes when the host run has finished and shutdown processing is complete. Remarks By default this method emits an informational shutdown log via logger.LogInformation(\u0022Run Exited - Shutting down\u0022) after host.RunAsync() completes. When StartupContext.ConsoleOutputMode is ConsoleOutputMode.CommandFirst , that shutdown log is suppressed so command-first console flows can keep help and validation output free of lifecycle noise. Logs a warning if shutdown is cancelled or does not complete in time. On an unhandled exception logs a critical error and sets Environment.ExitCode to -100 . Method CreateHostBuilder IHostBuilder IAppSurfaceStartup. CreateHostBuilder ( StartupContext context ) Creates an IHostBuilder configured for the provided startup context. Parameters context The startup context whose application name, modules, and registrations drive host configuration. Returns An IHostBuilder configured according to the given context . Method CreateHost IHost CreateHost ( StartupContext context ) Builds an IHost from the host builder configured for the provided startup context. Parameters context The startup context that provides application name, modules, and configuration used to construct the host. Returns The constructed IHost . Method CreateHostBuilderCore IHostBuilder CreateHostBuilderCore ( StartupContext context ) Create and configure a host builder using values from the provided startup context. Parameters context Startup context containing the application label, host application identity, root module, and dependencies used to configure the host builder. Returns A host builder configured with the context\u0027s host application identity, registered modules, and service registrations. Method CreateRootModule TRootModule CreateRootModule () Creates a new instance of the root module. Returns A new TRootModule instance. Method RegisterDependencies void RegisterDependencies ( StartupContext context ) Registers framework and root-module dependencies into the startup context once. Parameters context Startup context whose dependency graph should be prepared. Remarks App-type startups normally let AppSurface call this during host-builder creation. Specialized startup lifecycles may call it earlier when they need module-derived options before building the host. For example, CLI hosts that need packaged-asset or web-option defaults before the Generic Host exists should call RegisterDependencies(context) before reading those settings. The method adds Defaults.InternalServicesModule first, invokes IAppSurfaceModule.RegisterDependentModules(ModuleDependencyBuilder) on the root module, and then marks StartupContext.DependenciesRegistered so repeated calls are no-ops for the same context. This method is not thread-safe; access each StartupContext from a single thread during startup. Method ConfigureServicesForAppType void ConfigureServicesForAppType ( StartupContext context , IServiceCollection services ) Registers services required for the specific application type (for example, web or worker) into the provided service collection. Parameters context Startup context containing application metadata, dependencies, and configuration used during registration. services The service collection to which app-type-specific services should be added or overridden. Method ConfigureBuilderForAppType IHostBuilder ConfigureBuilderForAppType ( StartupContext context , IHostBuilder builder ) Allows the startup to customize the host builder for the specific application type. Parameters context The startup context containing application metadata and dependency modules. builder The host builder to customize. Returns The configured IHostBuilder (by default returns the provided builder unchanged). Type CommandResult Represents the captured result of a completed process execution. Parameters ExitCode The exit code returned by the process. A non-zero value indicates command failure, but it is still returned normally to the caller rather than being promoted to an exception. Stdout The exact text captured from standard output. This contains only the stdout stream and may be empty even when the process wrote diagnostics to standard error. Stderr The exact text captured from standard error. This contains only the stderr stream and may be empty even when the process produced standard output. Remarks Stdout and Stderr are captured independently per stream. They are not a merged chronological timeline, so callers that care about exact interleaving between standard output and standard error must preserve that ordering separately. ExitCode reflects the process exit value and may be non-zero without an exception being thrown. Startup failures and cancellation are surfaced as exceptions instead of a CommandResult . Type ProcessUtils Provides utility methods for executing external processes. Method ExecuteProcessAsync 2 overloads Task\u003CCommandResult\u003E ExecuteProcessAsync ( string fileName , IReadOnlyList\u003Cstring\u003E args , string workingDirectory , ILogger logger , CancellationToken cancellationToken , bool streamOutput = false , Func\u003Cstring, LogLevel\u003E? stderrLogLevelSelector = null ) Executes a process asynchronously and captures its output. Parameters fileName The path to the executable file to launch. args The ordered list of command-line arguments to pass to the process. workingDirectory The working directory used when starting the process. logger The logger that receives streamed output when streamOutput is true . cancellationToken A token to monitor for cancellation requests. streamOutput If true , standard output and standard error are logged in real time and also captured in the returned CommandResult . stderrLogLevelSelector Optional selector that can remap the log level used for each standard error line when streamOutput is enabled. When omitted, standard error lines are logged at LogLevel.Error . Returns A CommandResult containing the process exit code and captured standard output/error. Non-zero exit codes are returned to the caller and are not treated as exceptions. Exceptions OperationCanceledException Thrown when cancellationToken is canceled. InvalidOperationException Thrown if the process fails to start. Remarks When streamOutput is enabled, output is drained concurrently from both pipes, logged as lines arrive, and still buffered into the returned CommandResult . Any exception thrown by the logger or stderrLogLevelSelector is allowed to propagate so callers do not receive a partial success result with truncated output. The returned CommandResult preserves the exact standard output and standard error characters emitted by the process in both streaming and non-streaming modes. Task\u003CCommandResult\u003E ExecuteProcessAsync ( string fileName , IReadOnlyList\u003Cstring\u003E args , string workingDirectory , ILogger logger , CancellationToken cancellationToken , bool streamOutput , Func\u003Cstring, LogLevel\u003E? stderrLogLevelSelector , ProcessExecutionHooks? hooks ) Executes a process asynchronously with optional lifecycle hooks for deterministic testing. Parameters fileName The path to the executable file to launch. args The ordered list of command-line arguments to pass to the process. workingDirectory The working directory used when starting the process. logger The logger that receives streamed output when streamOutput is enabled. cancellationToken A token to monitor for cancellation requests. streamOutput If true , standard output and standard error are logged in real time and also captured in the returned CommandResult . stderrLogLevelSelector Optional selector that can remap the log level used for each standard error line when streamOutput is enabled. hooks Optional lifecycle hooks used by tests to simulate rare process runtime behaviors that are otherwise difficult to reproduce deterministically. Returns A CommandResult containing the process exit code and captured standard output/error. Method StreamToLoggerAsync Task\u003Cstring\u003E StreamToLoggerAsync ( TextReader reader , ILogger logger , LogLevel level , string fileName , CancellationToken cancellationToken , Func\u003Cstring, LogLevel\u003E? levelSelector = null ) Drains a text reader into a captured string while logging completed lines as they arrive. Parameters reader The reader to drain. logger The logger that receives completed output lines. level The default log level used for each completed line. fileName The process name included in structured log messages. cancellationToken The token used to cancel the drain operation. levelSelector Optional selector that can remap the log level used for each completed line. Returns The exact text captured from reader , including original line terminators. Exceptions OperationCanceledException Thrown when cancellationToken is canceled before the reader is fully drained. Any unterminated trailing line is intentionally not logged in that case. Remarks This method is internal so tests can deterministically verify the stream-drain and cancellation behavior without depending on timing-sensitive child-process races. Method GetResultAsync Task\u003Cstring\u003E GetResultAsync ( Task\u003Cstring\u003E? task ) Gets the result of a task if it is a Task\u003Cstring\u003E. Parameters task The task to observe. Returns The string result if available, otherwise an empty string. Method ObserveTaskAsync Task ObserveTaskAsync ( Task\u003Cstring\u003E? task , string streamName , string fileName , ILogger logger ) Observes a task during cleanup and logs any exceptions without surfacing them. Parameters task The task to observe. streamName The name of the stream (e.g., \u0022stdout\u0022). fileName The file name of the process being executed. logger The logger for debugging. Type ProcessExecutionHooks Test hooks that allow deterministic verification of process lifecycle edge cases. Remarks Use these hooks only from tests that need to simulate rare runtime conditions such as Process.Start() returning false or process termination throwing during cleanup. Production code should continue to use the public ExecuteProcessAsync(string, IReadOnlyList{string}, string, ILogger, CancellationToken, bool, Func{string, LogLevel}?) overload, which executes real process operations without overrides. Property StartProcessOverride Func\u003CProcess, bool\u003E? StartProcessOverride { get; init; } Gets or sets an optional process-start override. Property HasExitedOverride Func\u003CProcess, bool\u003E? HasExitedOverride { get; init; } Gets or sets an optional process-state override for Process.HasExited . Property KillProcessOverride Action\u003CProcess\u003E? KillProcessOverride { get; init; } Gets or sets an optional process-kill override used during cleanup. Type IAppSurfaceModule Defines a module that can configure services and register dependencies within the AppSurface host. Remarks Implement IAppSurfaceModule for reusable service-registration units that are not responsible for host lifecycle hooks. Create host-specific abstractions, or implement IAppSurfaceHostModule , when a module must configure hosting, middleware, endpoints, or other lifecycle behavior. Module methods run during startup; keep them idempotent, avoid heavy side effects and global state mutation, and throw clear configuration exceptions when required dependencies are missing. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Configures the services for this module. Parameters context The context for the current startup process. services The service collection to add registrations to. Remarks ConfigureServices should add deterministic registrations to services and should tolerate being called during host construction before the application is running. Do not resolve runtime services or perform blocking I/O here unless the module explicitly documents that startup cost. Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers other modules that this module depends on. Parameters builder The builder used to declare module dependencies. Remarks Dependencies should be declared before their services are required. ModuleDependencyBuilder handles duplicate module types and pre-registers modules to avoid recursive cycles, but modules should still avoid relying on incidental traversal order for behavior.","snippet":"Namespaces Defaults Extensions Type StartupContext Provides context and configuration during the application startup process. Parameters Args Command-line arguments provided to the application. RootModule The root...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-AppSurfaceStartup","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-AppSurfaceStartup","title":"AppSurfaceStartup","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","AppSurfaceStartup"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-AppSurfaceStartup"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-AppSurfaceStartup-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-AppSurfaceStartup-1","title":"AppSurfaceStartup\u003CTRootModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","AppSurfaceStartup\u003CTRootModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-AppSurfaceStartup-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-CommandResult","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-CommandResult","title":"CommandResult","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","CommandResult"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-CommandResult"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ConsoleOutputMode","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ConsoleOutputMode","title":"ConsoleOutputMode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","ConsoleOutputMode"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-ConsoleOutputMode"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-CriticalService","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-CriticalService","title":"CriticalService","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","CriticalService"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-CriticalService"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IAppSurfaceHostModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IAppSurfaceHostModule","title":"IAppSurfaceHostModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","IAppSurfaceHostModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-IAppSurfaceHostModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IAppSurfaceModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IAppSurfaceModule","title":"IAppSurfaceModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","IAppSurfaceModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-IAppSurfaceModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IAppSurfaceStartup","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IAppSurfaceStartup","title":"IAppSurfaceStartup","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","IAppSurfaceStartup"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-IAppSurfaceStartup"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IEnvironmentProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-IEnvironmentProvider","title":"IEnvironmentProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","IEnvironmentProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-IEnvironmentProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ModuleDependencyBuilder","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ModuleDependencyBuilder","title":"ModuleDependencyBuilder","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","ModuleDependencyBuilder"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-ModuleDependencyBuilder"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-PathUtils","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-PathUtils","title":"PathUtils","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","PathUtils"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-PathUtils"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ProcessUtils","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ProcessUtils","title":"ProcessUtils","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","ProcessUtils"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-ProcessUtils"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ProcessUtils-ProcessExecutionHooks","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-ProcessUtils-ProcessExecutionHooks","title":"ProcessExecutionHooks","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","ProcessExecutionHooks"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-ProcessUtils-ProcessExecutionHooks"},{"id":"Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-StartupContext","path":"/docs/Namespaces/ForgeTrust.AppSurface.Core.html#ForgeTrust-AppSurface-Core-StartupContext","title":"StartupContext","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Core","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Core","StartupContext"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Core#ForgeTrust-AppSurface-Core-StartupContext"},{"id":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html","title":"Autofac","summary":"Type AppSurfaceAutofacHostModule A base module that integrates Autofac into the AppSurface host lifecycle. Type AppSurfaceAutofacModule An Autofac Module wrapper that also participates in AppSurface module discovery....","headings":["AppSurfaceAutofacHostModule","AppSurfaceAutofacModule","ConfigureServices","RegisterDependentModules","AppSurfaceAutofacExtensions","RegisterImplementations","GetLoadableTypes"],"bodyText":"Type AppSurfaceAutofacHostModule A base module that integrates Autofac into the AppSurface host lifecycle. Type AppSurfaceAutofacModule An Autofac Module wrapper that also participates in AppSurface module discovery. Remarks AppSurfaceAutofacModule implements IAppSurfaceModule so Autofac-backed modules can be discovered with the rest of the AppSurface graph. Put Autofac registrations in normal Autofac module methods such as Module.Load(ContainerBuilder) ; ConfigureServices is intentionally a no-op for interface compatibility. Override RegisterDependentModules when this module requires other AppSurface modules. Pitfall: Autofac registration ordering and module dependencies still matter, so do not expect ConfigureServices to bridge Microsoft DI registrations into Autofac. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Intentionally does not register Microsoft DI services for this Autofac module. Parameters context The current startup context. services The Microsoft DI service collection, unused by this module. Remarks Use Autofac\u0027s Module.Load(ContainerBuilder) for registrations. This method exists only to satisfy IAppSurfaceModule . Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers AppSurface module dependencies required before this Autofac module is used. Parameters builder The module dependency builder used to declare prerequisites. Type AppSurfaceAutofacExtensions Provides extension methods for Autofac\u0027s ContainerBuilder to simplify common registrations. Remarks These helpers are convenience wrappers for assembly-scoped reflection scanning. Prefer explicit Autofac registration when ordering matters, multiple implementations need different lifetimes, startup performance is sensitive, or AOT/linker trimming must preserve only known types. Method RegisterImplementations 2 overloads IRegistrationBuilder\u003Cobject, ScanningActivatorData, DynamicRegistrationStyle\u003E RegisterImplementations \u003CTInterface\u003E ( this ContainerBuilder builder ) Registers all non-abstract class implementations of the specified interface type found in the interface\u0027s assembly. Type Parameters TInterface The interface type to scan for implementations of. Parameters builder The container builder. Returns A registration builder for the scanned types. Remarks This method scans only the assembly that declares TInterface and registers concrete, non-abstract assignable classes as TInterface services. It returns Autofac\u0027s IRegistrationBuilder{TLimit,TActivatorData,TRegistrationStyle} so callers can add lifetime, ownership, and metadata configuration. Use this helper when one interface owns a small assembly-local plugin surface and interface resolution is the intended contract. Prefer explicit registrations when implementations cross assemblies, require different service interfaces, need distinct lifetimes, or must be linker/AOT-friendly. Reflection scanning recovers from partial type-load failures by registering successfully loaded types only, so missing optional dependencies can still hide implementations that failed to load. IRegistrationBuilder\u003Cobject, ScanningActivatorData, DynamicRegistrationStyle\u003E RegisterImplementations \u003CTInterface\u003E ( this ContainerBuilder builder , Func\u003CAssembly, Type[]\u003E getTypes ) Registers implementations of TInterface using a caller-provided assembly type loader. Type Parameters TInterface The interface type to scan for implementations of. Parameters builder The container builder. getTypes Type loader for the assembly that declares TInterface . Returns A registration builder for the scanned types. Exceptions InvalidOperationException Thrown when getTypes completes successfully but returns null . Remarks This internal seam exists so tests can verify partial-load recovery without creating a broken fixture assembly. The getTypes delegate must return a non-null array for successful loads. If it throws ReflectionTypeLoadException , successfully loaded non-null entries from ReflectionTypeLoadException.Types are still registered and failed entries are ignored. Method GetLoadableTypes IEnumerable\u003CType\u003E GetLoadableTypes ( Assembly assembly , Func\u003CAssembly, Type[]\u003E getTypes ) Gets all loadable types from an assembly while tolerating partial reflection-load failures. Parameters assembly The assembly being scanned. getTypes The delegate used to load the assembly\u0027s type array. Returns All loaded types, or the non-null subset from ReflectionTypeLoadException.Types . Exceptions InvalidOperationException Thrown when getTypes completes successfully but returns null .","snippet":"Type AppSurfaceAutofacHostModule A base module that integrates Autofac into the AppSurface host lifecycle. Type AppSurfaceAutofacModule An Autofac Module wrapper that also participates in AppSurface module discovery....","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Autofac","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Dependency","Autofac"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac"},{"id":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacExtensions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacExtensions","title":"AppSurfaceAutofacExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Autofac","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Dependency","Autofac","AppSurfaceAutofacExtensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacExtensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacHostModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacHostModule","title":"AppSurfaceAutofacHostModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Autofac","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Dependency","Autofac","AppSurfaceAutofacHostModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacHostModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Dependency.Autofac.html#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacModule","title":"AppSurfaceAutofacModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Autofac","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Dependency","Autofac","AppSurfaceAutofacModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Dependency.Autofac#ForgeTrust-AppSurface-Dependency-Autofac-AppSurfaceAutofacModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Dependency.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Dependency.html","title":"Dependency","summary":"Namespaces Autofac","headings":[],"bodyText":"Namespaces Autofac","snippet":"Namespaces Autofac","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Dependency","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Dependency"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Dependency"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Controllers.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Controllers.html","title":"Controllers","summary":"Type DocsController Controller for serving documentation pages. Method Index Task\u003CIActionResult\u003E Index () Displays the documentation index view containing either curated proof paths from the repository-root landing...","headings":["DocsController","Index","VersionEntry","Versions","Section","Details","Search","SearchIndex","HarvestHealth","HarvestHealthJson","ShouldRefreshCache","CanRefreshCache","PrefixSearchIndexPathsForPathBase","IsApiSurfaceDoc","IsApiSurfacePageType","IsMarkdownDoc"],"bodyText":"Type DocsController Controller for serving documentation pages. Method Index Task\u003CIActionResult\u003E Index () Displays the documentation index view containing either curated proof paths from the repository-root landing doc metadata or the neutral docs landing fallback. Returns A view result whose model is a DocLandingViewModel . The model includes curated featured cards when the repository-root README.md metadata authors featured_page_groups through inline front matter or a paired sidecar such as README.md.yml ; otherwise it includes the neutral fallback landing data. Method VersionEntry IActionResult VersionEntry () Displays the stable docs entry fallback when versioning is enabled but the recommended released tree is not mounted. Returns A view result describing the available released versions plus the current preview surface, or a redirect to the live docs home when versioning is disabled. Method Versions IActionResult Versions () Displays the public docs version archive. Returns A view result that lists the published versions described by the configured version catalog, or a redirect to the live docs home when versioning is disabled. Method Section Task\u003CIActionResult\u003E Section ( string sectionSlug ) Enters one normalized public documentation section. Parameters sectionSlug The stable slug for the public section. Returns A redirect to the authored landing doc when one exists, otherwise a grouped section fallback or unavailable view. Method Details Task\u003CIActionResult\u003E Details ( string path ) Displays the full or partial details view for a documentation item identified by the given path. Parameters path The public docs route, redirect alias, or .partial.html resource identifier of the documentation item to retrieve. Full-page source-shaped Markdown routes for public pages redirect to the clean canonical route. Returns An IActionResult rendering the details view or the doc-content RazorWire frame; returns NotFoundResult when the path is invalid or no document is found after fallback resolution. Remarks Partial requests ending in .partial.html are resolved through the same DocAggregator.GetDocDetailsAsync(string, CancellationToken) flow as full-page requests. When a partial path resolves to an /index resource, such as /index.partial.html , the action transparently retries the parent document before returning NotFoundResult . Successful requests load the complete docs corpus and public-section snapshots with DocAggregator.GetDocsAsync(CancellationToken) and DocAggregator.GetPublicSectionsAsync(CancellationToken) , then build the response model with BuildDetailsViewModel . All aggregator calls observe HttpContext.RequestAborted . Visible caller side effects are limited to returning either the full details view or a doc-content frame for partial navigation. Method Search Task\u003CIActionResult\u003E Search () Displays the dedicated docs search workspace shell. Returns A ViewResult whose model is a SearchPageViewModel describing the search shell and its server-rendered recovery paths. Remarks The action returns a SearchPageViewModel immediately so the workspace can render starter, loading, and retry UI before the client downloads the search index. Fallback link generation shares a linked cancellation token with the current request and is capped by SearchShellFallbackBudget so slow aggregation does not block the shell from rendering. If aggregation times out or throws, the view still renders with default recovery links. Method SearchIndex Task\u003CIActionResult\u003E SearchIndex () Returns docs search index data for live-hosted docs. Returns A JSON result containing searchable document metadata, including normalized page-type badge fields that keep search result rendering consistent with the built-in landing and details experiences. When HttpRequest.PathBase is non-empty, only documents[*].path values that already start with / are rebased onto that path base before serialization so a mounted app returns links like /some-base/docs/guide.html instead of /docs/guide.html . Remarks The path-base rewrite is intentionally narrow. Only rooted documents[*].path values are prefixed; blank, missing, or already non-rooted values such as guide.html remain unchanged. The rewrite trims trailing slashes from the request path base before concatenation, so /some-base/ and /some-base produce the same output. For example, a typed payload that contains documents[0].path = \u0022/docs/guide.html\u0022 becomes /some-base/docs/guide.html when the request path base is /some-base . This action always receives the typed DocsSearchIndexPayload produced by DocAggregator.GetSearchIndexPayloadAsync(System.Threading.CancellationToken) ; raw JSON payloads without a top-level documents array are outside this method\u0027s contract and must be handled before this action is invoked. The rewrite is idempotent when HttpRequest.PathBase is null, empty, or / . Method HarvestHealth Task\u003CIActionResult\u003E HarvestHealth () Displays the redacted operator-facing harvest health page for the current live docs surface. Returns A health page when health routes are exposed for the current environment; otherwise NotFoundResult . Healthy and empty snapshots return HTTP 200. Degraded and failed snapshots render the same page with HTTP 503 so local verification and CI checks can fail quickly. Method HarvestHealthJson Task\u003CIActionResult\u003E HarvestHealthJson () Returns redacted machine-readable harvest health for the current live docs surface. Returns A JSON health response when health routes are exposed for the current environment; otherwise NotFoundResult . Healthy and empty snapshots return HTTP 200 with verification.ok=true . Degraded and failed snapshots return HTTP 503 with verification.ok=false . Method ShouldRefreshCache bool ShouldRefreshCache ( IQueryCollection query ) Determines whether the search index cache should be refreshed based on the presence of a \u0022refresh\u0022 query parameter. Parameters query The collection of query parameters from the HTTP request. Returns true if the cache should be refreshed; otherwise, false . Method CanRefreshCache bool CanRefreshCache () Checks whether the current user has permission to initiate a cache refresh. Returns true if the user is authenticated; otherwise, false . Method PrefixSearchIndexPathsForPathBase DocsSearchIndexPayload PrefixSearchIndexPathsForPathBase ( DocsSearchIndexPayload payload , string? requestPathBase ) Prefixes rooted search-document paths in a cached search-index payload for the active request path base. Parameters payload The cached search-index payload whose document paths may need rebasing. requestPathBase The current request path base that should be prepended when it is non-empty and not / . Returns The original payload when no rewrite is needed; otherwise a cloned payload whose rooted DocsSearchIndexDocument.Path values are prefixed with the normalized path base. Remarks This helper operates on the typed DocsSearchIndexPayload contract, which always exposes a top-level DocsSearchIndexPayload.Documents list. It does not inspect or reshape arbitrary JSON payloads, so callers that hold raw JSON without a top-level documents array must deserialize or otherwise handle that mismatch before calling this method. Within the typed payload, only rooted DocsSearchIndexDocument.Path values are rewritten. Non-rooted, blank, or otherwise unchanged values such as guide.html are returned as-is, so callers should supply leading-slash browser paths for docs-local navigation when rebasing is expected. For example, rebasing a payload that contains documents[0].path = \u0022/docs/guide.html\u0022 with /some-base/ produces /some-base/docs/guide.html . The supplied path base is trimmed of trailing slashes before concatenation, and the method is idempotent when requestPathBase is null, empty, or / . Method IsApiSurfaceDoc bool IsApiSurfaceDoc ( DocNode doc ) Determines whether a documentation node should render with the API reference reading surface. Remarks Non-Markdown generated docs use the API surface by default because RazorDocs cannot assume extensionless generated pages have authored prose rhythm. Markdown docs opt into the API surface only when page_type normalizes to api or api-reference . Extensionless authored content is therefore treated as generated API/reference content unless a future harvester exposes a stronger authorship signal. Method IsApiSurfacePageType bool IsApiSurfacePageType ( string? pageType ) Determines whether raw page-type metadata explicitly requests the API reference reading surface. Remarks Values are normalized with DocMetadataPresentation.NormalizeToken(string?) before comparison, so values such as api_reference and API Reference match api-reference . Null or blank metadata does not opt a Markdown document into the API surface. Method IsMarkdownDoc bool IsMarkdownDoc ( string path ) Determines whether a source path represents authored Markdown by checking known Markdown filename suffixes. Remarks Matching is case-insensitive and currently recognizes .md and .markdown . Callers should pass a non-null harvested path; extensionless paths are intentionally treated as non-Markdown generated docs.","snippet":"Type DocsController Controller for serving documentation pages. Method Index Task\u003CIActionResult\u003E Index () Displays the documentation index view containing either curated proof paths from the repository-root landing...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Controllers"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Controllers"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Controllers.html#ForgeTrust-AppSurface-Docs-Controllers-DocsController","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Controllers.html#ForgeTrust-AppSurface-Docs-Controllers-DocsController","title":"DocsController","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Controllers","DocsController"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Controllers#ForgeTrust-AppSurface-Docs-Controllers-DocsController"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html","title":"Docs","summary":"Namespaces Controllers Models Services Standalone ViewComponents Type RazorDocsVersionCatalog Declares the published RazorDocs versions that should be exposed through the version archive and static-tree mounting....","headings":["RazorDocsVersionCatalog","RecommendedVersion","Versions","RazorDocsPublishedVersion","Version","Label","Summary","ExactTreePath","SupportState","Visibility","AdvisoryState","RazorDocsVersionSupportState","RazorDocsVersionVisibility","RazorDocsVersionAdvisoryState","RazorDocsOptions","Mode","CacheExpirationMinutes","Source","Harvest","Bundle","Sidebar","Contributor","Routing","Versioning"],"bodyText":"Namespaces Controllers Models Services Standalone ViewComponents Type RazorDocsVersionCatalog Declares the published RazorDocs versions that should be exposed through the version archive and static-tree mounting. Remarks The catalog is the release-level source of truth for version routing and archive presentation. It does not describe individual documentation pages; instead it points at already-exported exact-version trees and records release state such as support posture, visibility, and advisory severity. The runtime validates each published tree independently so one broken version does not take down the whole docs host. Property RecommendedVersion string? RecommendedVersion { get; set; } Gets or sets the exact version that should also be exposed through the configured route-family root alias. Property Versions List\u003CRazorDocsPublishedVersion\u003E Versions { get; set; } Gets or sets the published versions known to the catalog. Type RazorDocsPublishedVersion Describes one published RazorDocs release tree. Property Version string Version { get; set; } Gets or sets the exact published version identifier, such as 0.4.0 or 1.2.3-rc.1 . Property Label string? Label { get; set; } Gets or sets the short reader-facing label for the release. Property Summary string? Summary { get; set; } Gets or sets optional summary copy shown in the version archive. Property ExactTreePath string? ExactTreePath { get; set; } Gets or sets the path to the exported exact-version docs subtree. Remarks The directory should contain the static files exported from the stable docs surface for one exact release, such as index.html , search-index.json , section routes, and detail pages. RazorDocs can then mount that same artifact at either RouteRootPath or {RouteRootPath}/v/{version} by rebasing stable-root links at response time. Relative paths resolve from the directory containing the version catalog file. Property SupportState RazorDocsVersionSupportState SupportState { get; set; } Gets or sets the support-state badge surfaced in the version archive. Property Visibility RazorDocsVersionVisibility Visibility { get; set; } Gets or sets the archive visibility behavior for the release. Property AdvisoryState RazorDocsVersionAdvisoryState AdvisoryState { get; set; } Gets or sets the release-level advisory state surfaced beside the version. Enum RazorDocsVersionSupportState Describes the support posture for one published docs release. Remarks Numeric values are explicit and stable because catalog payloads and downstream consumers may serialize or persist these states outside the current process. Enum RazorDocsVersionVisibility Controls whether a published version appears in the public archive and is mounted for static serving. Remarks Numeric values are explicit and stable because catalog payloads and downstream consumers may serialize or persist these states outside the current process. Enum RazorDocsVersionAdvisoryState Describes release-level advisory severity shown in the archive. Remarks Numeric values are explicit and stable because catalog payloads and downstream consumers may serialize or persist these states outside the current process. Type RazorDocsOptions Represents configuration for the RazorDocs package and host. Property Mode RazorDocsMode Mode { get; set; } Gets or sets the active docs source mode. Property CacheExpirationMinutes double CacheExpirationMinutes { get; set; } Gets or sets the absolute docs snapshot cache lifetime in minutes. The default is DefaultCacheExpirationMinutes minutes. Remarks This setting controls the shared aggregation snapshot used by docs pages, public-section data, and the generated search-index payload. Shorter values make source-backed development changes visible sooner, while longer values reduce repeated harvest and search-index generation work in production hosts. The value must be finite, must be between MinCacheExpirationMinutes and MaxCacheExpirationMinutes , and must represent a whole number of seconds because the generated search-index Cache-Control max-age header uses whole-second delta values. Values outside those constraints are rejected during options validation. Property Source RazorDocsSourceOptions Source { get; set; } Gets source-mode settings used when docs are harvested from a repository checkout. Property Harvest RazorDocsHarvestOptions Harvest { get; set; } Gets harvest policy settings used by runtime and export hosts. Property Bundle RazorDocsBundleOptions Bundle { get; set; } Gets bundle-mode settings used by future bundle-backed runtime loading. Property Sidebar RazorDocsSidebarOptions Sidebar { get; set; } Gets sidebar rendering settings. Property Contributor RazorDocsContributorOptions Contributor { get; set; } Gets contributor provenance settings used to render source, edit, and freshness evidence on details pages. Property Routing RazorDocsRoutingOptions Routing { get; set; } Gets routing settings that control where the live RazorDocs source surface is exposed. Property Versioning RazorDocsVersioningOptions Versioning { get; set; } Gets versioning settings used to mount exact release trees and the archive surface. Type RazorDocsSourceOptions Source-mode configuration for RazorDocs. Property RepositoryRoot string? RepositoryRoot { get; set; } Gets or sets the repository root used for source harvesting. When null, RazorDocs falls back to repository discovery from the content root. Type RazorDocsHarvestOptions Harvest policy settings for RazorDocs source-backed documentation. Remarks The default policy is tolerant so public runtime hosts can continue serving even when source harvesting has a transient problem. Enable FailOnFailure in CI or export hosts that should fail closed when every configured harvester fails, times out, or cancels. Property FailOnFailure bool FailOnFailure { get; set; } Gets or sets a value indicating whether host startup should fail when the aggregate harvest health is ForgeTrust.AppSurface.Docs.Models.DocHarvestHealthStatus.Failed . Remarks Strict mode treats only the aggregate failed state as fatal. Empty docs and degraded partial harvests remain non-fatal in this slice because they can represent intentional empty repositories or still-usable partial docs. Property Health RazorDocsHarvestHealthOptions Health { get; set; } Gets health-surface settings for the operator-facing RazorDocs harvest health routes and sidebar chrome. Type RazorDocsHarvestHealthOptions Operator-facing harvest health settings for RazorDocs. Remarks The health surface exposes the same cached harvest state returned by ForgeTrust.AppSurface.Docs.Services.DocAggregator.GetHarvestHealthAsync(System.Threading.CancellationToken) . Development hosts show the route response and sidebar chrome by default so local failures are visible immediately. Other environments must opt in explicitly before RazorDocs returns health responses or displays sidebar chrome. Property ExposeRoutes RazorDocsHarvestHealthExposure ExposeRoutes { get; set; } Gets or sets when RazorDocs should return health responses from {DocsRootPath}/_health and {DocsRootPath}/_health.json . Remarks The default is RazorDocsHarvestHealthExposure.DevelopmentOnly . RazorDocs always reserves these route patterns ahead of the docs catch-all route so they do not fall through to document lookup. Setting this to RazorDocsHarvestHealthExposure.Always allows the controller actions to return operator-facing responses in non-development hosts; protect those responses with host-owned authentication, authorization, or network controls when they are reachable by untrusted users. Property ShowChrome RazorDocsHarvestHealthExposure ShowChrome { get; set; } Gets or sets when RazorDocs should show the harvest health entry in the built-in docs sidebar. Remarks This option is intentionally independent from ExposeRoutes so hosts can expose a machine-readable endpoint without advertising it in the docs chrome, or show local-development chrome without changing non-development route behavior. Type RazorDocsBundleOptions Bundle-mode configuration for RazorDocs. Property Path string? Path { get; set; } Gets or sets the path to the docs bundle payload. Type RazorDocsSidebarOptions Sidebar presentation settings for RazorDocs. Property NamespacePrefixes string[] NamespacePrefixes { get; set; } Gets or sets configured namespace prefixes for sidebar label simplification. Type RazorDocsContributorOptions Contributor-provenance configuration for RazorDocs details pages. Remarks This contract controls the global contributor-provenance surface. Use Enabled to switch the entire feature on or off for a host, and use page-level contributor metadata to suppress or override individual pages without mutating host-wide defaults. Property Enabled bool Enabled { get; set; } Gets or sets a value indicating whether contributor provenance rendering is enabled for RazorDocs details pages. Disable this when the host should suppress all contributor affordances, even if page-level overrides or trustworthy source paths exist. When false , RazorDocs also skips contributor-template startup validation because the feature is globally inactive. Property DefaultBranch string? DefaultBranch { get; set; } Gets or sets the stable branch name used when expanding configured source and edit URL templates. Required when Enabled is true and either SourceUrlTemplate or EditUrlTemplate is configured, and used as the fallback source ref for symbol links when SourceRef is not configured. Property SourceUrlTemplate string? SourceUrlTemplate { get; set; } Gets or sets the source-link template. Supported tokens are {branch} and {path} . Configured templates must include {path} so each page expands to its own source location when Enabled is true . Property EditUrlTemplate string? EditUrlTemplate { get; set; } Gets or sets the edit-link template. Supported tokens are {branch} and {path} . Configured templates must include {path} when Enabled is true . Prefer this when maintainers should land directly in an edit workflow rather than in repository browsing. Property SymbolSourceUrlTemplate string? SymbolSourceUrlTemplate { get; set; } Gets or sets the source-link template for generated C# API symbols. Supported tokens are {path} , {line} , {branch} , and {ref} . Configured templates must include {path} and {line} when Enabled is true , and unsupported token placeholders are rejected during startup validation. Use {ref} when links should prefer a commit SHA supplied through SourceRef and fall back to DefaultBranch . Property SourceRef string? SourceRef { get; set; } Gets or sets the source-control ref used for generated C# API symbol links. Prefer a commit SHA when the docs build knows one. When omitted, symbol links that use {ref} fall back to DefaultBranch so hosts can still render moving-branch links intentionally. Property LastUpdatedMode RazorDocsLastUpdatedMode LastUpdatedMode { get; set; } Gets or sets the mode used to resolve contributor freshness. The default is RazorDocsLastUpdatedMode.None so hosts opt into git-backed freshness explicitly instead of paying unexpected snapshot-time git costs. RazorDocsLastUpdatedMode.Git uses local repository history when a trustworthy source path exists and omits only freshness when git data is unavailable or untrustworthy. Type RazorDocsRoutingOptions Routing settings for the RazorDocs route family and live source surface. Remarks RazorDocs separates the route-family root from the live docs root. RouteRootPath owns stable entry, archive, and exact-version routes. DocsRootPath owns the live source-backed surface used for current docs, search, and the current search-index payload. For a custom versioned host, use values such as RouteRootPath=/foo/bar and DocsRootPath=/foo/bar/next . Both values are normalized into app-relative paths during AddRazorDocs() post-configuration. Property RouteRootPath string? RouteRootPath { get; set; } Gets or sets the app-relative route-family root for this RazorDocs instance. Remarks The route root is the parent for stable entry, archive, and exact-version routes. When omitted, it defaults to the live docs root with versioning disabled and to /docs with versioning enabled. Relative-looking values are normalized into app-relative paths. For example, foo/bar becomes /foo/bar . Use / for a single-purpose root-mounted docs host. The normalized path must not end with / , include query or fragment segments, or target reserved child routes such as /foo/bar/versions or /foo/bar/v . Property DocsRootPath string? DocsRootPath { get; set; } Gets or sets the app-relative root path for the live source-backed docs surface. Remarks The live root serves current source-backed docs, search, and the current search index. Relative-looking values are normalized into app-relative paths. For example, foo/bar/next becomes /foo/bar/next . When versioning is disabled the default path is the route root. When versioning is enabled the default path is {RouteRootPath}/next , or /docs/next for the default route family. The live root must not collide with the route-family root or its reserved archive/exact-version children when versioning is enabled. Type RazorDocsVersioningOptions Versioning settings for published RazorDocs release trees. Remarks Enabling versioning turns on the published-release route contract: RazorDocsRoutingOptions.RouteRootPath for the recommended release alias, {RouteRootPath}/v/{version} for immutable exact trees, {RouteRootPath}/versions for the archive, and a live preview surface rooted at RazorDocsRoutingOptions.DocsRootPath . The catalog stays file-based in this slice: runtime consumes a JSON manifest plus prebuilt exact release trees and does not perform Git or bundle resolution at request time. The catalog must describe the recommended version alias plus one or more exact release trees whose exported contents satisfy the exact-tree contract documented in the package README. Property Enabled bool Enabled { get; set; } Gets or sets a value indicating whether release-tree versioning is enabled. Property CatalogPath string? CatalogPath { get; set; } Gets or sets the path to the version catalog JSON file. Remarks This property is required when Enabled is true . The catalog describes available exact-version trees, the recommended version alias, and release-level status metadata such as support and advisory state. Relative paths resolve from the app content root. The JSON payload is expected to contain a top-level recommended version plus a versions array whose entries point at exported exact-version trees. A missing, unreadable, or malformed catalog does not crash RazorDocs, but it leaves all published releases unavailable until the catalog can be loaded successfully. When Enabled is true and this property is blank, startup validation fails before the app begins serving requests. Type RazorDocsOptionsValidator Validates RazorDocsOptions and rejects unsupported or ambiguous startup configurations. Enum RazorDocsMode Enumerates the supported RazorDocs content source modes. Remarks Numeric values are part of the public configuration and serialization contract. Do not reorder or renumber existing members; changing these assignments can break persisted configuration, serialized payloads, and consumers. Add new modes by appending members with new explicit values. Enum RazorDocsHarvestHealthExposure Enumerates environment-aware exposure policies for RazorDocs harvest health surfaces. Remarks Numeric values are part of the public configuration and serialization contract. Do not reorder or renumber existing members; changing these assignments can break persisted configuration, serialized payloads, and consumers. Add new modes by appending members with new explicit values. Enum RazorDocsLastUpdatedMode Enumerates the supported contributor freshness modes for RazorDocs details pages. Remarks Numeric values are part of the public configuration and serialization contract. Do not reorder or renumber existing members; changing these assignments can break persisted configuration, serialized payloads, and consumers. Add new modes by appending members with new explicit values. Type RazorDocsUrlHelperExtensions Provides Razor view helpers for emitting app-relative RazorDocs links that honor the active request path base. Method PathBaseAware string PathBaseAware ( this IUrlHelper url , string? href ) Rewrites rooted app-relative href values through IUrlHelper.Content(string) so mounted hosts keep their current PathBase , while leaving non-rooted URLs unchanged. Parameters url The active URL helper for the rendered view. href The href to normalize for rendering. Returns A path-base-aware href for rooted docs links, the original non-rooted href for relative/external links, or an empty string when href is blank. Protocol-relative URLs such as //cdn.example.com/app.css are preserved as-is so they do not get mistaken for app-relative docs links. Type RazorDocsWebModule Web module configuration for the RazorDocs documentation system. Remarks This module owns both the live source-backed RazorDocs surface and the optional published-version overlay used when RazorDocsVersioningOptions.Enabled is turned on. Service registration wires up harvesting, aggregation, sanitization, URL generation, and version-catalog resolution through services.AddRazorDocs() , while endpoint and middleware hooks decide whether the host behaves like a plain live docs site or a mixed live-plus-archive experience. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Registers services required by the RazorDocs module into the provided service collection. Remarks Adds the RazorDocs harvesting, aggregation, and sanitization services via services.AddRazorDocs() . RazorDocs styling is compiled into the package during the RazorDocs build and the layout resolves the correct static asset path for root-module versus embedded consumer hosts, so hosts do not register services.AddTailwind() just to light up the embedded docs UI. Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers runtime module dependencies for this web module, including RazorWireWebModule. Parameters builder The dependency builder used to register required modules. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , IHostBuilder builder ) Performs host-level configuration steps before application services are registered. Parameters context The startup context providing module and environment information. builder The host builder to configure prior to service registration. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , IHostBuilder builder ) Performs host-level configuration steps after application services have been registered. Parameters context The startup context providing module and environment information. builder The host builder to modify or extend after services are configured. Method ConfigureWebApplication void ConfigureWebApplication ( StartupContext context , IApplicationBuilder app ) Configures the application\u0027s request pipeline and middleware for this module. Parameters context The startup context for the module invocation. app The application builder used to configure middleware and endpoints. Remarks This hook only mutates the pipeline when versioning is enabled and the resolved RazorDocsVersionCatalogService yields at least one available published tree. In that case the module mounts exact-version exports, optionally adds the configured route-family root alias for the recommended release, and inserts a short-circuiting middleware branch that lets RazorDocsPublishedTreeHandler serve matching requests before the live preview surface sees them. Method BuildPublishedTreeMounts (IReadOnlyList\u003CRazorDocsPublishedTreeMount\u003E Mounts, IReadOnlyList\u003CPhysicalFileProvider\u003E Providers) BuildPublishedTreeMounts ( RazorDocsResolvedVersionCatalog catalog , DocsUrlBuilder docsUrlBuilder ) Builds the published-tree mount table for the current resolved version catalog. Parameters catalog The resolved version catalog that describes available published trees. docsUrlBuilder The configured URL builder that supplies the route-family alias root. Returns The ordered mount list plus the unique provider instances that should be disposed with the host lifetime. Remarks Public exact-version mounts always preserve the authored catalog order. When the recommended release points at a public exact tree, this helper adds the configured route-family root alias as an extra mount root that reuses the same PhysicalFileProvider instance instead of duplicating file watchers for the same export path. Method ConfigureEndpoints void ConfigureEndpoints ( StartupContext context , IEndpointRouteBuilder endpoints ) Adds the module\u0027s default controller routes and supporting asset routes for documentation endpoints. Parameters context Startup context for the application and environment. endpoints Endpoint route builder used to map the module\u0027s routes. Remarks When RazorDocs is the root module assembly, standalone and static-export hosts preserve the historical /css/site.gen.css URL by redirecting it to the packaged Razor Class Library stylesheet at /_content/ForgeTrust.AppSurface.Docs/css/site.gen.css . Embedded hosts do not register that redirect because they already link to the packaged asset directly. Redirects preserve the request HttpRequest.PathBase and query string so legacy links continue to work behind a virtual path, but the path base and configured package target must remain single-slash app-relative path components. When versioning is enabled, this hook also reserves the stable version entry route at the configured route-family root, adds the archive surface below that route root, and serves preview-surface assets from either the live web root or the packaged Razor Class Library depending on whether published-tree mounts can shadow the stable docs root. Asset routes are built with DocsUrlBuilder.BuildAssetUrl(string) for search.css , minisearch.min.js , search-client.js , and the page-local outline-client.js . Preview hosts can serve those files directly from the web root; otherwise the current-surface URLs redirect through ResolveLegacySearchAssetBasePath to the packaged RazorDocs assets. Legacy asset redirects preserve only the request query string, while the redirect path itself is constrained to an app-relative URL so cache-busting parameters cannot turn the redirect into an external hop. Route ordering matters: index, search, search-index, section, and catch-all routes are registered from most to least specific so the live preview root continues to behave correctly even when the current docs root is root-mounted or overlaps published exact-version aliases. When RazorDocs is the root module, the bare application root redirects to the configured docs home. This keeps standalone docs hosts and static exports useful after route isolation removed the old app-wide controller fallback. Embedded hosts do not get this redirect; their owning app should decide what / means. The operator-facing harvest health route patterns are always registered before the catch-all docs route so {DocsRootPath}/_health and {DocsRootPath}/_health.json remain reserved operator paths rather than falling through to document lookup. The route named razordocs_harvest_health maps the current docs root health pattern from DocsUrlBuilder.BuildHealthUrl to DocsController.HarvestHealth , and razordocs_harvest_health_json maps DocsUrlBuilder.BuildHealthJsonUrl to DocsController.HarvestHealthJson . The controller actions still gate responses with RazorDocsHarvestHealthVisibility.AreRoutesExposed(RazorDocsOptions, IHostEnvironment) : by default they return health only in Development, while production hosts must opt in with RazorDocsHarvestHealthOptions.ExposeRoutes . These routes are intended for local and operator verification, not as unauthenticated public reader navigation. Method BuildLegacyAssetRedirectPath string BuildLegacyAssetRedirectPath ( PathString pathBase , string targetPath , QueryString queryString ) Builds the local redirect target used when historical docs asset URLs move to packaged Razor Class Library assets. Parameters pathBase The current request path base to preserve for applications mounted below a prefix. targetPath The package asset path selected by RazorDocs endpoint configuration. queryString The request query string to preserve for cache-busting or diagnostics parameters. Returns An escaped, single-slash app-relative redirect target with the original query string appended. Exceptions InvalidOperationException Thrown when pathBase or targetPath is not a safe app-relative path component. Remarks This helper intentionally treats query text as data appended after the validated path. It validates the unescaped path base so unsafe separators are not hidden by URI formatting, then emits the escaped path base used for redirect headers. A root path base ( / ) is normalized to empty so the redirect stays single-slash local. It does not allow the path base or target path to be absolute, protocol-relative, backslash-prefixed, or control-character-bearing because those shapes can be interpreted by clients as redirects away from the current host. Type RazorDocsServiceCollectionExtensions Registers the RazorDocs dependency injection and options normalization pipeline. Remarks This extension binds RazorDocsOptions from configuration, rehydrates omitted nested option objects such as RazorDocsOptions.Harvest , RazorDocsOptions.Routing , and RazorDocsOptions.Versioning with their default containers, normalizes caller-provided string settings, and validates the final shape on startup. Callers should use this once per application when they want the standard RazorDocs harvesting, routing, preview, and versioned published-release services to be available to downstream modules and controllers. Method AddRazorDocs IServiceCollection AddRazorDocs ( this IServiceCollection services ) Adds the RazorDocs package services, normalized options, and routing helpers to the service collection. Parameters services The target service collection. Returns The same service collection for chaining. Remarks During post-configuration this method rehydrates null nested option blocks with defaults, trims nullable string settings such as repository roots and contributor URL templates, normalizes RazorDocsRoutingOptions.RouteRootPath and RazorDocsRoutingOptions.DocsRootPath through DocsUrlBuilder.NormalizeRouteRootPath(string?, string, bool) and DocsUrlBuilder.NormalizeDocsRootPath(string?, bool) , trims RazorDocsVersioningOptions.CatalogPath , and removes blank or duplicate sidebar namespace prefixes. Callers that omit RazorDocsOptions.Routing or RazorDocsOptions.Versioning can therefore still rely on a fully populated options object after registration. When RazorDocsHarvestOptions.FailOnFailure is enabled, the registered startup preflight fails the host only when the aggregate harvest health is failed. When RazorDocsRoutingOptions.DocsRootPath is omitted or whitespace, the live docs root is derived from the normalized RazorDocsRoutingOptions.RouteRootPath through DocsUrlBuilder.ResolveDefaultDocsRootPath(string, bool) . For example, RazorDocs:Routing:RouteRootPath=/foo/bar with versioning enabled produces /foo/bar/next as the default live root. Callers that set both RazorDocsRoutingOptions.RouteRootPath and RazorDocsRoutingOptions.DocsRootPath should keep the pair coherent so stable entry, archive, exact-version, and live preview routes compose predictably after DocsUrlBuilder.NormalizeRouteRootPath(string?, string, bool) and DocsUrlBuilder.NormalizeDocsRootPath(string?, bool) run. The method also registers DocsUrlBuilder and RazorDocsVersionCatalogService as singleton downstream services alongside the standard harvesters, memo cache, and DocAggregator . Consumers that resolve RazorDocsOptions directly should expect the normalized values rather than raw configuration text, and applications that need custom routing or catalog paths should provide those values before this method runs so the normalized singleton graph stays consistent. Type RazorDocsAssetPathResolver Resolves stylesheet paths for RazorDocs hosts. Remarks When the current application\u0027s root module lives in the RazorDocs assembly, RazorDocs layouts preserve the historical root stylesheet URL at ~/css/site.gen.css . Published and exported hosts may only materialize the packaged Razor Class Library asset path, so RazorDocsWebModule also preserves the root URL via a compatibility redirect to ~/_content/ForgeTrust.AppSurface.Docs/css/site.gen.css . When RazorDocs is consumed from another host assembly, layouts link directly to that packaged asset path. Method CreateDefault RazorDocsAssetPathResolver CreateDefault () Creates the default asset-path resolver used when only the RazorDocs services are registered. Returns A resolver that assumes RazorDocs is embedded in another host. Method CreateForRootModule RazorDocsAssetPathResolver CreateForRootModule ( Assembly rootModuleAssembly ) Creates the asset-path resolver for the supplied root module assembly. Parameters rootModuleAssembly The assembly that owns the current host\u0027s root module. Returns The resolver that matches the current host\u0027s RazorDocs asset layout. Method IsRootModuleAssembly bool IsRootModuleAssembly ( Assembly rootModuleAssembly ) Determines whether the supplied root module assembly belongs to the RazorDocs standalone host. Parameters rootModuleAssembly The assembly that owns the current host\u0027s root module. Returns true when RazorDocs is the root module; otherwise, false . Property StylesheetPath string StylesheetPath { get; } Gets the application-relative stylesheet path to use from RazorDocs layouts.","snippet":"Namespaces Controllers Models Services Standalone ViewComponents Type RazorDocsVersionCatalog Declares the published RazorDocs versions that should be exposed through the version archive and static-tree mounting....","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsAssetPathResolver","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsAssetPathResolver","title":"RazorDocsAssetPathResolver","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsAssetPathResolver"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsAssetPathResolver"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsBundleOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsBundleOptions","title":"RazorDocsBundleOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsBundleOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsBundleOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsContributorOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsContributorOptions","title":"RazorDocsContributorOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsContributorOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsContributorOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsHarvestHealthExposure","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsHarvestHealthExposure","title":"RazorDocsHarvestHealthExposure","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsHarvestHealthExposure"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsHarvestHealthExposure"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsHarvestHealthOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsHarvestHealthOptions","title":"RazorDocsHarvestHealthOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsHarvestHealthOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsHarvestHealthOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsHarvestOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsHarvestOptions","title":"RazorDocsHarvestOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsHarvestOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsHarvestOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsLastUpdatedMode","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsLastUpdatedMode","title":"RazorDocsLastUpdatedMode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsLastUpdatedMode"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsLastUpdatedMode"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsMode","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsMode","title":"RazorDocsMode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsMode"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsMode"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsOptions","title":"RazorDocsOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsOptionsValidator","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsOptionsValidator","title":"RazorDocsOptionsValidator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsOptionsValidator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsOptionsValidator"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsPublishedVersion","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsPublishedVersion","title":"RazorDocsPublishedVersion","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsPublishedVersion"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsPublishedVersion"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsRoutingOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsRoutingOptions","title":"RazorDocsRoutingOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsRoutingOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsRoutingOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsServiceCollectionExtensions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsServiceCollectionExtensions","title":"RazorDocsServiceCollectionExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsServiceCollectionExtensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsServiceCollectionExtensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsSidebarOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsSidebarOptions","title":"RazorDocsSidebarOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsSidebarOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsSidebarOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsSourceOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsSourceOptions","title":"RazorDocsSourceOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsSourceOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsSourceOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsUrlHelperExtensions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsUrlHelperExtensions","title":"RazorDocsUrlHelperExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsUrlHelperExtensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsUrlHelperExtensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionAdvisoryState","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionAdvisoryState","title":"RazorDocsVersionAdvisoryState","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsVersionAdvisoryState"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsVersionAdvisoryState"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionCatalog","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionCatalog","title":"RazorDocsVersionCatalog","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsVersionCatalog"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsVersionCatalog"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersioningOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersioningOptions","title":"RazorDocsVersioningOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsVersioningOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsVersioningOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionSupportState","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionSupportState","title":"RazorDocsVersionSupportState","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsVersionSupportState"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsVersionSupportState"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionVisibility","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsVersionVisibility","title":"RazorDocsVersionVisibility","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsVersionVisibility"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsVersionVisibility"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsWebModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.html#ForgeTrust-AppSurface-Docs-RazorDocsWebModule","title":"RazorDocsWebModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","RazorDocsWebModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs#ForgeTrust-AppSurface-Docs-RazorDocsWebModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html","title":"Models","summary":"Type DocPageTypeBadgePresentation Presentation metadata for one normalized documentation page-type badge. Property Value string Value { get; init; } Gets the normalized machine-readable page-type value. Property Label...","headings":["DocPageTypeBadgePresentation","Value","Label","Variant","DocMetadataPresentation","ResolvePageTypeBadge","NormalizeToken","DocMetadata","Title","Summary","SummaryIsDerived","PageType","Audience","Component","Aliases","RedirectAliases","Keywords","Status","NavGroup","Order","SequenceKey","SectionLanding","HideFromPublicNav","HideFromSearch"],"bodyText":"Type DocPageTypeBadgePresentation Presentation metadata for one normalized documentation page-type badge. Property Value string Value { get; init; } Gets the normalized machine-readable page-type value. Property Label string Label { get; init; } Gets the human-readable badge label. Property Variant string Variant { get; init; } Gets the badge variant suffix used by built-in RazorDocs CSS classes such as docs-page-badge--guide . Type DocMetadataPresentation Converts raw documentation metadata values into consistent UI-facing labels and badge variants. Remarks Use this helper from Razor views, search payload generation, or custom UI surfaces when you want the built-in RazorDocs page-type treatment to remain consistent across landing, detail, and search experiences. Method ResolvePageTypeBadge DocPageTypeBadgePresentation? ResolvePageTypeBadge ( string? pageType ) Resolves the built-in RazorDocs page-type badge presentation for a raw metadata value. Parameters pageType The raw page-type metadata value, such as guide , api-reference , or release-note . Returns A normalized badge presentation when pageType is non-empty; otherwise, null . Release aliases such as release-note and release-notes resolve to the canonical release badge value. Unknown page types fall back to a neutral badge with a title-cased label. Method NormalizeToken string? NormalizeToken ( string? value ) Normalizes a raw metadata token into a lowercase dash-delimited value. Parameters value Raw metadata token that may contain whitespace, underscores, dashes, or line breaks. Returns A normalized token, or null when value is null, whitespace, or produces no non-delimiter segments after trimming and splitting. Remarks RazorDocs trims the input, splits on spaces, tabs, carriage returns, line feeds, underscores, and hyphens, removes empty segments, lowercases each remaining segment, and rejoins them with - . Type DocMetadata Structured metadata that can drive navigation, breadcrumbs, related links, and search without re-parsing source content. Property Title string? Title { get; init; } Gets the resolved display title for the documentation node. Property Summary string? Summary { get; init; } Gets a short summary describing the documentation node. Property SummaryIsDerived bool? SummaryIsDerived { get; init; } Gets a value indicating whether Summary was derived from page content instead of authored explicitly. Property PageType string? PageType { get; init; } Gets the page type, such as guide, example, api-reference, or troubleshooting. Property Audience string? Audience { get; init; } Gets the intended audience for the page. Property Component string? Component { get; init; } Gets the product component associated with the page. Property Aliases IReadOnlyList\u003Cstring\u003E? Aliases { get; init; } Gets alternate terms that should resolve to this page in search. Property RedirectAliases IReadOnlyList\u003Cstring\u003E? RedirectAliases { get; init; } Gets alternate route aliases that should redirect to the canonical page when redirect support is enabled. Property Keywords IReadOnlyList\u003Cstring\u003E? Keywords { get; init; } Gets search keywords associated with the page. Property Status string? Status { get; init; } Gets the content lifecycle status for the page. Property NavGroup string? NavGroup { get; init; } Gets the navigation group used by public docs navigation. Property Order int? Order { get; init; } Gets the relative ordering value within a navigation group. Property SequenceKey string? SequenceKey { get; init; } Gets the explicit sequence identifier used to connect pages into one proof path. Remarks RazorDocs does not infer sequence membership from folders or filenames in this slice. Pages participate in next/previous wayfinding only when authors opt them into the same SequenceKey and assign comparable Order values. Property SectionLanding bool? SectionLanding { get; init; } Gets a value indicating whether the page is the authored landing doc for its public section. Property HideFromPublicNav bool? HideFromPublicNav { get; init; } Gets a value indicating whether the page should be hidden from public navigation. Property HideFromSearch bool? HideFromSearch { get; init; } Gets a value indicating whether the page should be hidden from search. Property RelatedPages IReadOnlyList\u003Cstring\u003E? RelatedPages { get; init; } Gets related page identifiers or titles. Property CanonicalSlug string? CanonicalSlug { get; init; } Gets the preferred canonical slug for the page. Property Breadcrumbs IReadOnlyList\u003Cstring\u003E? Breadcrumbs { get; init; } Gets optional human-readable breadcrumb labels for the page. Property FeaturedPageGroups IReadOnlyList\u003CDocFeaturedPageGroupDefinition\u003E? FeaturedPageGroups { get; init; } Gets optional landing-page curation groups authored with the documentation page. Remarks RazorDocs parses this metadata on any page so the contract stays page-agnostic. Authors can supply groups either inline in Markdown front matter or through a paired sidecar such as README.md.yml . The built-in docs landing consumes the repository-root README.md groups, and section landing docs consume their own groups for reader-intent next steps. Property Trust DocTrustMetadata? Trust { get; init; } Gets optional trust and provenance metadata rendered near the top of the page. Remarks This nested object is designed for release notes, upgrade policies, changelogs, and similar pages that need to communicate current status, adoption safety, and archival provenance without custom view logic. Property Contributor DocContributorMetadata? Contributor { get; init; } Gets optional contributor provenance metadata for page-level source, edit, and freshness control. Property BreadcrumbsMatchPathTargets bool? BreadcrumbsMatchPathTargets { get; init; } Gets a value indicating whether authored breadcrumb labels align with the path-derived breadcrumb targets that RazorDocs can safely reuse for rendering. Type DocOutlineItem Represents one navigable heading captured while harvesting a documentation page. Property Title string Title { get; init; } Gets the heading text shown in the page-local outline and search metadata. Property Id string Id { get; init; } Gets the HTML fragment identifier that anchors this outline item within the page. Property Level int Level { get; init; } Gets the normalized heading level for this entry. Type DocTrustMetadata Structured trust and provenance metadata for a documentation page. Property Status string? Status { get; init; } Gets the compact top-level state shown in the trust bar, such as Unreleased or Pre-1.0 policy . Property Summary string? Summary { get; init; } Gets the short trust statement that explains what the current status means for readers. Property Freshness string? Freshness { get; init; } Gets the freshness statement that explains how current or provisional the page is. Property ChangeScope string? ChangeScope { get; init; } Gets the statement describing which product surfaces or artifacts this page covers. Property Migration DocTrustLink? Migration { get; init; } Gets an optional link to migration or upgrade guidance. Property Archive string? Archive { get; init; } Gets the archival or long-term home statement for the page contents. Property Sources IReadOnlyList\u003Cstring\u003E? Sources { get; init; } Gets optional provenance notes or upstream sources that support the page. Type DocTrustLink Link metadata used by trust-bar actions such as migration guidance. Property Label string? Label { get; init; } Gets the reader-facing link label. Property Href string? Href { get; init; } Gets the browser-facing destination URL. Type DocContributorMetadata Page-level contributor provenance metadata used to override or suppress source, edit, and freshness evidence. Method Merge DocContributorMetadata? Merge ( DocContributorMetadata? primary , DocContributorMetadata? fallback ) Merges contributor metadata by preferring authored primary values and filling missing values from fallback metadata. Remarks Precedence rules: HideContributorInfo uses nullable-boolean precedence, so explicit false is preserved. SourcePathOverride , SourceUrlOverride , and EditUrlOverride prefer the first non-blank string; whitespace-only values are treated as missing. LastUpdatedOverride uses null coalescing and therefore keeps the primary timestamp when present. Pitfalls: Setting a string override to the empty string does not clear a fallback value; it falls back instead. Callers that need to suppress inherited contributor rendering should use HideContributorInfo instead of relying on blank string overrides. Property HideContributorInfo bool? HideContributorInfo { get; init; } Gets a value indicating whether contributor provenance should be hidden for the page even when automatic evidence exists. Property SourcePathOverride string? SourcePathOverride { get; init; } Gets an optional repository-relative source-path override used for source links, edit links, and git freshness resolution. Rooted paths and traversal segments are rejected. Property SourceUrlOverride string? SourceUrlOverride { get; init; } Gets an optional explicit source URL override. Only absolute HTTP(S) URLs and root-relative paths are accepted. Property EditUrlOverride string? EditUrlOverride { get; init; } Gets an optional explicit edit URL override. Only absolute HTTP(S) URLs and root-relative paths are accepted. Property LastUpdatedOverride DateTimeOffset? LastUpdatedOverride { get; init; } Gets an optional exact timestamp override for contributor freshness. Type DocSymbolSourceProvenance Identifies the source declaration that produced one rendered C# API documentation symbol. Property AnchorId string AnchorId { get; init; } Gets the rendered HTML anchor ID for the generated API symbol. Property SourcePath string SourcePath { get; init; } Gets the repository-relative source file path that contains the documented declaration. Property StartLine int StartLine { get; init; } Gets the 1-based source declaration line. Type DocNode Represents a documentation node within the repository. Parameters Title The display title of the document. Path The relative path to the documentation source. Content The rendered HTML content of the documentation. ParentPath The optional parent path for hierarchical organization. IsDirectory Indicates if this node represents a directory container. CanonicalPath The browser-facing docs route path used for linking and lookup. Metadata Structured metadata associated with the documentation node. Outline Structured in-page outline entries captured during harvesting. SymbolSourceProvenance Optional source declarations keyed by rendered C# API symbol anchor IDs. Type DocHarvestHealthSnapshot Captures the structured health of one RazorDocs harvest snapshot. Parameters Status Overall health rollup for the snapshot. GeneratedUtc UTC timestamp when the snapshot was generated. RepositoryRoot Repository root passed to configured harvesters. Treat this as server-only operational data because it can contain sensitive or environment-specific filesystem paths; redact or omit it before sending snapshots to clients. TotalHarvesters Number of harvesters configured for the snapshot. SuccessfulHarvesters Number of harvesters that completed with either docs or a valid empty result. FailedHarvesters Number of harvesters that failed, timed out, or canceled. TotalDocs Number of documentation nodes published by the final cached docs snapshot. Harvesters Per-harvester health entries. Never null in RazorDocs-created snapshots. Diagnostics Structured diagnostics for failed, degraded, or noteworthy states. Never null in RazorDocs-created snapshots. Remarks RazorDocs-created snapshots retain non-null Harvesters and Diagnostics collections for safe server-side inspection, but callers that serialize this record into client-visible payloads must sanitize RepositoryRoot first. Type DocHarvesterHealth Captures one configured harvester\u0027s status inside a RazorDocs harvest snapshot. Parameters HarvesterType Concrete harvester type name used in logs and diagnostics. Status Harvester-level health status. DocCount Number of documentation nodes returned by the harvester before RazorDocs post-processing. Diagnostic Diagnostic explaining a failed, timed-out, or canceled harvester; usually null for non-failure outcomes. Type DocHarvestDiagnostic Describes one structured RazorDocs harvest health diagnostic. Parameters Code Stable diagnostic code suitable for tests, logs, documentation, and host UI branching. Severity Diagnostic severity. HarvesterType Concrete harvester type when the diagnostic belongs to one harvester, or null for aggregate diagnostics. Problem Operator-facing summary of what went wrong. Cause Explanation of why RazorDocs could not safely treat the harvest as fully healthy. Fix Suggested operator or docs-author action that resolves the problem. Type DocHarvestDiagnosticCodes Defines the stable diagnostic codes emitted by RazorDocs harvest health snapshots. Remarks Use these constants when testing or branching on DocHarvestDiagnostic.Code values. The string values are public compatibility contracts and must not be changed once released. Type DocSectionSnapshot Represents one normalized public-section snapshot derived from the harvested docs corpus. Property Section DocPublicSection Section { get; init; } Gets the typed public section identifier. Property Label string Label { get; init; } Gets the canonical display label for the section. Property Slug string Slug { get; init; } Gets the stable route slug for the section. Property LandingDoc DocNode? LandingDoc { get; init; } Gets the optional authored landing doc that represents the section. Property VisiblePages IReadOnlyList\u003CDocNode\u003E VisiblePages { get; init; } Gets the public pages that belong to the section, ordered for display. Type DocFeaturedPageGroupDefinition Defines one authored reader-intent group for a docs landing surface. Property Intent string? Intent { get; init; } Gets the stable reader-intent identifier for the group. Remarks Authors may omit this value when Label is present. RazorDocs derives a normalized intent from the label during metadata parsing so downstream resolvers can still identify the group consistently. Property Label string? Label { get; init; } Gets the reader-facing group heading. Remarks Authors may omit this value when Intent is present. RazorDocs converts the intent into a title-cased label during metadata parsing so the landing can still render a useful heading. Property Summary string? Summary { get; init; } Gets optional copy that explains when a reader should choose the group. Property Order int? Order { get; init; } Gets the relative display order for the group. Property Pages IReadOnlyList\u003CDocFeaturedPageDefinition\u003E Pages { get; init; } Gets the featured destination pages in this group. Property SourceFieldPath string? SourceFieldPath { get; init; } Gets the parser-populated metadata field path for group-level diagnostics. Remarks This internal value is for diagnostics and source attribution only. Authored metadata and consumers should not depend on it as stable content because the parser path format may change. Type DocFeaturedPageDefinition Defines one authored featured-page entry for a docs landing surface. Property Question string? Question { get; init; } Gets the reader-facing evaluator question or label for the card. Remarks When this value is omitted on the built-in docs landing, RazorDocs falls back to the resolved destination page title so the card still renders with a sensible label. Property Path string? Path { get; init; } Gets the source or canonical path of the destination page to feature. Remarks RazorDocs matches both source paths and canonical browser paths. Path separators are normalized during resolution so authored forward-slash and backslash forms point to the same destination. Property SupportingCopy string? SupportingCopy { get; init; } Gets optional landing-only supporting copy shown instead of destination summary text. Property Order int? Order { get; init; } Gets the relative display order for the featured entry. Property SourceFieldPath string? SourceFieldPath { get; init; } Gets the parser-populated metadata field path for page-level diagnostics. Remarks This internal value is for diagnostics and source attribution only. Authored metadata and consumers should not depend on it as stable content because the parser path format may change. Type DocLandingViewModel View model for the docs landing page. Property Heading string Heading { get; init; } Gets the hero heading shown on the docs landing. Property Description string Description { get; init; } Gets the supporting description shown under the hero heading. Property LandingDoc DocNode? LandingDoc { get; init; } Gets the repository-root landing document when one was harvested. Property StartHereHref string? StartHereHref { get; init; } Gets the href for the section-level Start Here route when that section exists in the current public docs corpus. Property VisibleDocs IReadOnlyList\u003CDocNode\u003E VisibleDocs { get; init; } Gets the visible documentation nodes used by the neutral fallback landing state. Property FeaturedPageGroups IReadOnlyList\u003CDocLandingFeaturedPageGroupViewModel\u003E FeaturedPageGroups { get; init; } Gets the resolved proof-path groups for the landing experience. Property SecondarySections IReadOnlyList\u003CDocHomeSectionViewModel\u003E SecondarySections { get; init; } Gets the secondary section summaries shown under the primary Start Here route. Property HasFeaturedPages bool HasFeaturedPages { get; } Gets a value indicating whether the landing should render a proof-path lead section. Type DocLandingFeaturedPageGroupViewModel View model for one resolved reader-intent group on a docs landing page. Remarks Intent and Label are normalized by the featured-page resolver before rendering: authored whitespace is trimmed, missing labels fall back to the resolved intent, and both values are non-null. Summary contains optional group copy and may be null . Pages contains the resolved DocLandingFeaturedPageViewModel rows produced by the resolver after it matches authored destinations to visible docs. Empty Pages lists are treated as no featured pages and are suppressed by DocLandingViewModel.HasFeaturedPages , DocDetailsViewModel.HasFeaturedPages , and the RazorDocs views. Pitfalls: callers should not rely on an empty Pages list being rendered, and should expect Intent , Label , Summary , and Pages to reflect resolver output rather than raw authored front matter. Property Intent string Intent { get; init; } Gets the stable reader-intent identifier for the group. Property Label string Label { get; init; } Gets the reader-facing group label. Property Summary string? Summary { get; init; } Gets optional copy that explains when to choose this group. Property Pages IReadOnlyList\u003CDocLandingFeaturedPageViewModel\u003E Pages { get; init; } Gets the resolved featured-page rows in this group. Type DocLandingFeaturedPageViewModel View model for one resolved featured card on the docs landing page. Property Question string Question { get; init; } Gets the evaluator question or label shown on the card. Property Title string Title { get; init; } Gets the destination page title shown on the card. Property Href string Href { get; init; } Gets the browser-facing link to the destination page. Property PageType string? PageType { get; init; } Gets the destination page type, such as guide, example, or api-reference. Property PageTypeBadge DocPageTypeBadgePresentation? PageTypeBadge { get; init; } Gets the normalized badge presentation for PageType when RazorDocs can render one. Property SupportingText string? SupportingText { get; init; } Gets the supporting body copy shown on the card. Type DocHomeSectionViewModel View model describing one secondary public-section summary on the docs home. Property Section DocPublicSection Section { get; init; } Gets the typed public section represented by the summary. Property Label string Label { get; init; } Gets the section label shown to the reader. Property Slug string Slug { get; init; } Gets the stable route slug for the section. Property Href string Href { get; init; } Gets the route that enters the section. Property Purpose string Purpose { get; init; } Gets the one-sentence utility copy that explains what the reader can do in the section. Property KeyRoutes IReadOnlyList\u003CDocSectionLinkViewModel\u003E KeyRoutes { get; init; } Gets the key routes surfaced for the section on the docs home. Type DocBreadcrumbViewModel View model for a section-scoped or doc-scoped breadcrumb item. Property Label string Label { get; init; } Gets the breadcrumb label shown to the reader. Property Href string? Href { get; init; } Gets the optional target href for the breadcrumb. Type DocSectionLinkViewModel View model for one section list or sidebar link. Property Title string Title { get; init; } Gets the displayed link title. Property Href string Href { get; init; } Gets the destination href. Property Summary string? Summary { get; init; } Gets optional utility copy shown with the link. Property Eyebrow string? Eyebrow { get; init; } Gets optional short eyebrow text shown above the link title. Property PageTypeBadge DocPageTypeBadgePresentation? PageTypeBadge { get; init; } Gets the normalized page-type badge for the destination when one is available. Property Children IReadOnlyList\u003CDocSectionLinkViewModel\u003E Children { get; init; } Gets nested child links shown under the current link. Property UseAnchorNavigation bool UseAnchorNavigation { get; init; } Gets a value indicating whether the link should use docs anchor navigation semantics. Property IsCurrent bool IsCurrent { get; init; } Gets a value indicating whether this link represents the current page. Type DocSectionGroupViewModel View model for one grouped set of section links. Property Title string? Title { get; init; } Gets the optional group heading shown above the link list. Property Links IReadOnlyList\u003CDocSectionLinkViewModel\u003E Links { get; init; } Gets the links that belong to the group. Type DocPageLinkViewModel View model for one resolved documentation link shown in related or sequence wayfinding. Property Title string Title { get; init; } Gets the destination page title. Property Href string Href { get; init; } Gets the browser-facing destination URL. Property Summary string? Summary { get; init; } Gets optional supporting text for the destination. Property PageTypeBadge DocPageTypeBadgePresentation? PageTypeBadge { get; init; } Gets the normalized page type badge metadata for the destination when available. Type DocSidebarViewModel View model for the sidebar navigation shell. Property Sections IReadOnlyList\u003CDocSidebarSectionViewModel\u003E Sections { get; init; } Gets the sections shown in the sidebar. Property HarvestHealth DocSidebarHarvestHealthViewModel? HarvestHealth { get; init; } Gets the harvest health sidebar entry when the current host should show health chrome. Type DocSidebarHarvestHealthViewModel View model for the RazorDocs harvest health sidebar entry. Property Status string Status { get; init; } Gets the aggregate harvest status label. Property Ok bool Ok { get; init; } Gets a value indicating whether the status should pass local or CI verification. Property Href string? Href { get; init; } Gets the app-relative health page route when health routes are exposed; otherwise null for status-only chrome. Type DocSidebarSectionViewModel View model for one public section in the sidebar. Property Section DocPublicSection Section { get; init; } Gets the typed section represented by the sidebar entry. Property Label string Label { get; init; } Gets the section label shown in the sidebar. Property Slug string Slug { get; init; } Gets the stable section slug. Property Href string Href { get; init; } Gets the section route href. Property IsActive bool IsActive { get; init; } Gets a value indicating whether the section owns the current page context. Property IsExpanded bool IsExpanded { get; init; } Gets a value indicating whether the section should render expanded by default. Property Groups IReadOnlyList\u003CDocSectionGroupViewModel\u003E Groups { get; init; } Gets the grouped links rendered when the section is expanded. Type DocSectionPageViewModel View model for the grouped-section fallback and unavailable section surfaces. Property Section DocPublicSection? Section { get; init; } Gets the typed section when the route resolved to a known built-in section. Property Heading string Heading { get; init; } Gets the section label or unavailable-page heading. Property Description string Description { get; init; } Gets the primary explanatory copy for the page. Property DocsHomeHref string DocsHomeHref { get; init; } Gets the docs home route. Property StartHereHref string? StartHereHref { get; init; } Gets the href for the section-level Start Here route when that section exists in the current public docs corpus. Property IsUnavailable bool IsUnavailable { get; init; } Gets a value indicating whether the route resolved to an unavailable section surface. Property AvailabilityMessage string? AvailabilityMessage { get; init; } Gets the explanatory copy shown when the section is unavailable. Property IsSparse bool IsSparse { get; init; } Gets a value indicating whether the fallback section is intentionally sparse. Property KeyRoutes IReadOnlyList\u003CDocSectionLinkViewModel\u003E KeyRoutes { get; init; } Gets the key routes surfaced for a sparse section fallback. Property Groups IReadOnlyList\u003CDocSectionGroupViewModel\u003E Groups { get; init; } Gets the grouped page lists shown for the section. Type DocDetailsViewModel View model for a rendered documentation details page. Property Document DocNode Document { get; init; } Gets the underlying documentation node. Property Outline IReadOnlyList\u003CDocOutlineItem\u003E Outline { get; init; } Gets the in-page outline entries for the current document. Property PreviousPage DocPageLinkViewModel? PreviousPage { get; init; } Gets the previous page within the current authored sequence, when one exists. Property NextPage DocPageLinkViewModel? NextPage { get; init; } Gets the next page within the current authored sequence, when one exists. Property RelatedPages IReadOnlyList\u003CDocPageLinkViewModel\u003E RelatedPages { get; init; } Gets the authored related pages that resolved successfully. Property ContributorProvenance DocContributorProvenanceViewModel? ContributorProvenance { get; init; } Gets the contributor provenance evidence resolved for the current page. Property Title string Title { get; init; } Gets the resolved display title for the page. Property Summary string? Summary { get; init; } Gets the authored summary that should be rendered under the title when available. Property ShowSummary bool ShowSummary { get; init; } Gets a value indicating whether Summary should be rendered. Property IsCSharpApiDoc bool IsCSharpApiDoc { get; init; } Gets a value indicating whether the page is a C# API reference document. Property IsApiSurfaceDoc bool IsApiSurfaceDoc { get; init; } Gets a value indicating whether the page should use the API reference reading surface. Remarks This covers non-Markdown generated documents and Markdown documents explicitly marked with API-oriented metadata, while IsCSharpApiDoc remains scoped to C# generated page chrome decisions. Property PageTypeBadge DocPageTypeBadgePresentation? PageTypeBadge { get; init; } Gets the normalized page-type badge presentation for the current page when available. Property Component string? Component { get; init; } Gets the explicit component metadata shown with the page when available. Property Audience string? Audience { get; init; } Gets the explicit audience metadata shown with the page when available. Property Breadcrumbs IReadOnlyList\u003CDocBreadcrumbViewModel\u003E Breadcrumbs { get; init; } Gets the breadcrumb trail used by the page. Property PublicSection DocPublicSection? PublicSection { get; init; } Gets the current public section when the page belongs to a public docs section. Property PublicSectionLabel string? PublicSectionLabel { get; init; } Gets the current public-section label when one exists. Property PublicSectionHref string? PublicSectionHref { get; init; } Gets the current public-section route href when one exists. Property PublicSectionPurpose string? PublicSectionPurpose { get; init; } Gets the current public-section utility sentence when one exists. Property TrustMigrationUsesTurbo bool TrustMigrationUsesTurbo { get; init; } Gets a value indicating whether the trust-bar migration link should stay inside the docs content frame. Remarks This is resolved from the harvested docs corpus rather than inferred from the raw href alone so root-mounted docs surfaces can still treat canonical plain .html docs routes as docs-local without misclassifying unrelated site pages. Property ContributorSourceUsesTurbo bool ContributorSourceUsesTurbo { get; init; } Gets a value indicating whether the contributor source link should stay inside the docs content frame. Remarks This is resolved from the harvested docs corpus rather than inferred from the raw href alone so mounted or root-hosted docs surfaces can keep local provenance links inside the docs shell without trapping unrelated app routes. Property ContributorEditUsesTurbo bool ContributorEditUsesTurbo { get; init; } Gets a value indicating whether the contributor edit link should stay inside the docs content frame. Remarks This follows the same docs-local resolution contract as ContributorSourceUsesTurbo so preview, versioned, and root-mounted docs surfaces all make the same frame-targeting decision. Property IsSectionLanding bool IsSectionLanding { get; init; } Gets a value indicating whether the current document is a section landing doc. Property FeaturedPageGroups IReadOnlyList\u003CDocLandingFeaturedPageGroupViewModel\u003E FeaturedPageGroups { get; init; } Gets the curated next-step groups shown by a section landing doc. Property HasFeaturedPages bool HasFeaturedPages { get; } Gets a value indicating whether any curated section-landing group has visible next-step pages. Property SectionGroups IReadOnlyList\u003CDocSectionGroupViewModel\u003E SectionGroups { get; init; } Gets the grouped In this section lists shown by a section landing doc. Property HasOutline bool HasOutline { get; } Gets a value indicating whether the page has an in-page outline to render. Property HasWayfinding bool HasWayfinding { get; } Gets a value indicating whether the page has any sequence or related-page wayfinding links to render. Type DocContributorProvenanceViewModel View model describing the contributor provenance evidence rendered near the top of a details page. Property Label string Label { get; init; } Gets the reader-facing provenance strip label. Property SourceHref string? SourceHref { get; init; } Gets the browser-facing source URL when one exists. Property EditHref string? EditHref { get; init; } Gets the browser-facing edit URL when one exists. Property LastUpdatedUtc DateTimeOffset? LastUpdatedUtc { get; init; } Gets the exact UTC timestamp used for contributor freshness when one exists. Type IDocHarvester Interface for harvesting documentation from various sources. Method HarvestAsync Task\u003CIReadOnlyList\u003CDocNode\u003E\u003E HarvestAsync ( string rootPath , CancellationToken cancellationToken = default ) Asynchronously scans the specified root path and returns a collection of documentation nodes harvested from sources under that path. Parameters rootPath The filesystem root path to scan for documentation sources. cancellationToken An optional token to observe for cancellation requests. Returns A collection of DocNode representing the harvested documentation. Enum DocHarvestHealthStatus Describes the overall health of the latest RazorDocs harvest snapshot. Remarks Numeric values are a stable public compatibility contract for persisted and serialized representations. Do not remove, reorder, or renumber existing members. Enum DocHarvesterHealthStatus Describes one configured harvester\u0027s contribution to a RazorDocs harvest snapshot. Remarks Numeric values are a stable public compatibility contract for persisted and serialized representations. Do not remove, reorder, or renumber existing members. Enum DocHarvestDiagnosticSeverity Describes the severity of a structured RazorDocs harvest diagnostic. Remarks Numeric values are a stable public compatibility contract for persisted and serialized representations. Do not remove, reorder, or renumber existing members. Enum DocPublicSection Enumerates the built-in public documentation sections used by RazorDocs. Remarks Numeric values are a stable public compatibility contract for persisted and serialized representations. Do not remove, reorder, or renumber existing members. Presentation order is defined by DocPublicSectionCatalog.OrderedSections , so renderers should not infer UI ordering from enum ordinals. Type RazorDocsHarvestFailedException Exception thrown by strict RazorDocs startup preflight when every configured harvester fails. Remarks The exception message and Summary intentionally contain only redacted harvest-health fields. Repository roots, raw exception messages, stack traces, and diagnostic cause text stay in host logs and are not copied into this public failure contract. Property Summary DocHarvestFailureSummary Summary { get; } Gets the redacted strict-harvest failure summary. Type DocHarvestFailureSummary Redacted strict-harvest failure summary safe for public exception messages and export output. Parameters Status The aggregate harvest-health status that triggered strict failure. GeneratedUtc The timestamp for the cached harvest snapshot generation. TotalHarvesters Number of configured harvesters in the failed snapshot. SuccessfulHarvesters Number of harvesters that completed with docs or an intentional empty result. FailedHarvesters Number of harvesters that failed, timed out, or canceled. TotalDocs Number of final docs in the failed snapshot. Diagnostics Redacted diagnostic entries copied from the failed snapshot. Method FromSnapshot DocHarvestFailureSummary FromSnapshot ( DocHarvestHealthSnapshot health ) Creates a redacted strict-harvest failure summary from a harvest-health snapshot. Parameters health The harvest-health snapshot to summarize. Returns A redacted summary that omits repository roots, raw exception details, and diagnostic cause text. Type DocHarvestFailureDiagnostic Redacted strict-harvest diagnostic safe for public exception messages and export output. Parameters Code Stable diagnostic code for machine-readable branching and tests. Severity Diagnostic severity copied from the source diagnostic. HarvesterType Concrete harvester type when the diagnostic belongs to one harvester. Problem Operator-facing problem statement. Fix Suggested recovery action. Method FromDiagnostic DocHarvestFailureDiagnostic FromDiagnostic ( DocHarvestDiagnostic diagnostic ) Creates a redacted strict-harvest diagnostic from a harvest-health diagnostic. Parameters diagnostic The source diagnostic to redact. Returns A diagnostic that omits cause text and raw exception details. Type RazorDocsVersionArchiveViewModel View model for the public RazorDocs version archive and degraded entry surface. Remarks The same model drives both the dedicated archive page and the degraded route-root recovery surface when no healthy recommended release can be mounted at the stable entry alias. PreviewHref always points at the current source-backed preview surface, while VersionsHref stays on the stable archive URL. Versions preserves the authored catalog order and should be treated as a read-only projection of the resolved catalog state. Property Heading string Heading { get; init; } Gets the page heading. Property Description string Description { get; init; } Gets the orientation copy shown above the archive list. Property AvailabilityMessage string? AvailabilityMessage { get; init; } Gets optional explanatory copy shown when the stable route-root alias cannot mount a recommended released tree. Remarks This is typically null on the dedicated archive page and populated only for the degraded route-root recovery experience. Property PreviewHref string PreviewHref { get; init; } Gets the live preview docs URL. Remarks This points at the configured source-backed preview surface, such as /docs/next for the default route family or /foo/bar/next for a custom one. Property VersionsHref string VersionsHref { get; init; } Gets the stable archive URL. Property Versions IReadOnlyList\u003CRazorDocsVersionArchiveEntryViewModel\u003E Versions { get; init; } Gets the available published versions shown in the archive. Type RazorDocsVersionArchiveEntryViewModel Represents one release entry in the public RazorDocs version archive. Remarks Entries may describe either a healthy exact-version tree with an Href target or an unavailable release that should remain visible in the archive with an explanatory availability message. IsRecommended identifies the exact release currently mirrored at the stable route-root alias, while IsAvailable controls whether the entry can link directly to that exact version. Advisory and support labels are independent: an unavailable or deprecated release may still surface an advisory, and a recommended release may still carry a warning label when the catalog says readers should see one. Property Version string Version { get; init; } Gets the exact published version identifier. Property Label string Label { get; init; } Gets the reader-facing label. Property Summary string? Summary { get; init; } Gets optional summary copy for the release. Property Href string? Href { get; init; } Gets the exact-version URL when the release is available. Remarks This is null when IsAvailable is false and the archive should render the release as informational-only. Property IsRecommended bool IsRecommended { get; init; } Gets a value indicating whether this version is the recommended stable alias target. Property IsAvailable bool IsAvailable { get; init; } Gets a value indicating whether the exact-version tree is currently available. Property SupportStateLabel string SupportStateLabel { get; init; } Gets the human-readable support-state label. Property AdvisoryLabel string? AdvisoryLabel { get; init; } Gets the human-readable advisory label when a release warning should be surfaced. Remarks This is null when no release-level warning badge should be rendered. Property AvailabilityMessage string? AvailabilityMessage { get; init; } Gets the availability explanation when the release tree is unavailable. Remarks This is usually populated only when IsAvailable is false and explains why the exact-version tree could not be mounted or linked. Type SearchPageViewModel Describes the server-rendered shell for the dedicated docs search workspace. Parameters Title The primary page heading shown above the workspace controls. Orientation A short orientation sentence that explains what users can discover from the workspace. StarterHint Helper copy shown in the starter state before a query or filter is applied. SearchPlaceholder Placeholder text for the advanced search input. SuggestedQueries Starter-state suggestions rendered as clickable chips. Empty lists are allowed, but the shell is designed around a curated set of useful first queries. FailureFallbackLinks Ordered recovery links shown when the search runtime or index cannot be loaded. Include at least one non-search path that still helps users continue through the docs set. Remarks This model is rendered before the client-side search index is available so the page can show stable loading, starter, and failure states even when the search payload is slow or unavailable. All members are required and should be supplied as non- null values. The list properties render in the order provided. Use SearchPageViewModel for the server-rendered shell contract and recovery guidance, not for live search results or client-side facet state. Callers should prefer empty lists over null for SuggestedQueries and FailureFallbackLinks . Suggested queries and fallback links are displayed in the supplied order, so place the highest-signal actions first. Avoid relying on client-side mutation of this model after render, and avoid using external absolute URLs in SearchPageFallbackLink.Href because the shell assumes app-relative navigation semantics. Type SearchPageFallbackLink Represents one server-rendered recovery action shown when docs search cannot be initialized. Parameters Title Short, action-oriented label used as the visible link title. Href The app-relative destination URL to open when the user follows the recovery action. Description Supporting context that explains what the destination contains and why it helps recover from the failed search flow. UsesDocsFrame A value indicating whether the destination should stay inside the docs content frame. Set this to true only when the destination is known to be another docs page rather than a top-level recovery surface such as the docs home or version archive. Remarks These links are rendered before the client search payload is available, so each entry should be complete enough to stand on its own. UsesDocsFrame determines whether the destination should continue navigating inside the docs content frame or escalate to a top-level page navigation. Keep Href app-relative and already URL-safe, and assume the UI will HTML-escape the visible text in Title and Description . Prefer concise copy that fits comfortably in a compact recovery card, and do not depend on client search indexing to make the destination discoverable. Type RazorDocsHarvestHealthResponse Redacted operator-facing RazorDocs harvest health response shared by the HTML and JSON health surfaces. Remarks This contract intentionally omits repository roots, diagnostic cause text, raw exception messages, stack traces, and other host-local details. Use DocAggregator.GetHarvestHealthAsync(System.Threading.CancellationToken) for server-side inspection when trusted code needs the full snapshot. Method FromSnapshot RazorDocsHarvestHealthResponse FromSnapshot ( DocHarvestHealthSnapshot health ) Creates a redacted response from the full server-side harvest health snapshot. Parameters health The server-side harvest health snapshot. Returns A response that is safe to serialize to clients. Property Status string Status { get; init; } Gets the aggregate harvest status name. Property GeneratedUtc DateTimeOffset GeneratedUtc { get; init; } Gets the UTC timestamp when the cached harvest snapshot was generated. Property Verification RazorDocsHarvestHealthVerification Verification { get; init; } Gets the machine-checkable verification rollup for the response. Property TotalHarvesters int TotalHarvesters { get; init; } Gets the number of configured harvesters in the snapshot. Property SuccessfulHarvesters int SuccessfulHarvesters { get; init; } Gets the number of harvesters that completed with docs or a valid empty result. Property FailedHarvesters int FailedHarvesters { get; init; } Gets the number of harvesters that failed, timed out, or canceled. Property TotalDocs int TotalDocs { get; init; } Gets the number of documentation nodes published by the final cached docs snapshot. Property Harvesters IReadOnlyList\u003CRazorDocsHarvesterHealthResponse\u003E Harvesters { get; init; } Gets the per-harvester redacted health entries. Property Diagnostics IReadOnlyList\u003CRazorDocsHarvestDiagnosticResponse\u003E Diagnostics { get; init; } Gets redacted diagnostic entries for failed, degraded, or noteworthy states. Type RazorDocsHarvestHealthVerification Machine-checkable verification rollup for a RazorDocs harvest health response. Property Ok bool Ok { get; init; } Gets a value indicating whether the harvest state should pass local or CI verification. Property HttpStatusCode int HttpStatusCode { get; init; } Gets the HTTP status code RazorDocs uses for this response. Type RazorDocsHarvesterHealthResponse Redacted per-harvester health entry in the operator-facing harvest health response. Property HarvesterType string HarvesterType { get; init; } Gets the concrete harvester type name. Property Status string Status { get; init; } Gets the harvester status name. Property DocCount int DocCount { get; init; } Gets the number of documentation nodes returned by the harvester before RazorDocs post-processing. Property Diagnostic RazorDocsHarvestDiagnosticResponse? Diagnostic { get; init; } Gets the redacted diagnostic explaining a failed, timed-out, or canceled harvester. Type RazorDocsHarvestDiagnosticResponse Redacted diagnostic entry in the operator-facing harvest health response. Property Code string Code { get; init; } Gets the stable diagnostic code. Property Severity string Severity { get; init; } Gets the diagnostic severity name. Property HarvesterType string? HarvesterType { get; init; } Gets the concrete harvester type when the diagnostic belongs to one harvester. Property Problem string Problem { get; init; } Gets the operator-facing problem statement. Property Fix string Fix { get; init; } Gets the suggested operator or docs-author recovery action. Type DocPublicSectionCatalog Defines the canonical public-section labels, slugs, purpose copy, and alias lookup rules used by RazorDocs. Method GetLabel string GetLabel ( DocPublicSection section ) Gets the canonical display label for the specified public section. Parameters section The section whose label should be returned. Returns The reader-facing label, such as Start Here or API Reference . Method GetSlug string GetSlug ( DocPublicSection section ) Gets the canonical stable route slug for the specified public section. Parameters section The section whose slug should be returned. Returns A lower-case hyphenated slug suitable for {DocsRootPath}/sections/{slug} routes. Method GetPurpose string GetPurpose ( DocPublicSection section ) Gets the short purpose statement used to explain why a public section exists. Parameters section The section whose purpose copy should be returned. Returns The summary text shown in section-first navigation surfaces. Method GetHref 2 overloads string GetHref ( DocPublicSection section ) Gets the default stable public route for the specified section. Parameters section The section whose href should be returned. Returns The default /docs/sections/{slug} route for the section. Remarks This overload always roots the returned href at the default /docs surface. Callers that are rendering links on the current live surface should prefer GetHref(DocPublicSection, string) so custom route roots and preview roots are honored. The route slug is always produced by GetSlug(DocPublicSection) . string GetHref ( DocPublicSection section , string docsRootPath ) Gets the canonical public-section route rooted at the caller\u0027s current docs surface. Parameters section The section whose href should be returned. docsRootPath The pre-normalized, app-relative docs root path to anchor the section route under. Callers are expected to pass the validated live docs root from RazorDocsRoutingOptions.DocsRootPath or Services.DocsUrlBuilder.CurrentDocsRootPath , not an arbitrary or unvalidated value. Returns The canonical {docsRootPath}/sections/{slug} route for the section, or /sections/{slug} when docsRootPath is exactly / . Remarks This overload exists for mounted live docs surfaces such as /docs/next or root-mounted docs at / . It special-cases / so root-mounted hosts emit /sections/{slug} instead of //sections/{slug} . The slug portion is always derived from GetSlug(DocPublicSection) . Passing a non-normalized value such as /docs/ can produce incorrect hard-coded links, so callers should normalize and validate docsRootPath before invoking this overload. Method TryResolve bool TryResolve ( string? value , out DocPublicSection section ) Resolves an authored section value using canonical labels, canonical slugs, or known aliases. Parameters value The authored value to resolve. section When this method returns true , contains the resolved public section. Returns true when value matches a known label, slug, or alias after normalization; otherwise, false . Remarks Resolution is case-insensitive and ignores surrounding whitespace plus non-alphanumeric separators so values such as Start Here , start-here , and start_here all resolve to the same section. Method TryResolveSlug bool TryResolveSlug ( string? slug , out DocPublicSection section ) Resolves only canonical section-route slugs for /docs/sections/{slug} URLs. Parameters slug The incoming route slug to resolve. section When this method returns true , contains the resolved public section. Returns true when slug matches one canonical section slug after trimming and case-normalization; otherwise, false . Remarks Unlike TryResolve , this method does not accept labels or aliases. Callers that want to support legacy or user-friendly alias inputs should resolve them separately and redirect to GetHref(DocPublicSection) . Method BuildLookup IReadOnlyDictionary\u003Cstring, DocPublicSection\u003E BuildLookup () Builds the lookup table used for authored metadata values that may use labels, slugs, or aliases. Returns A normalized dictionary that maps authored section identifiers to their canonical section enum. Method BuildSlugLookup IReadOnlyDictionary\u003Cstring, DocPublicSection\u003E BuildSlugLookup () Builds the lookup table used for canonical section-route slugs. Returns A normalized dictionary that accepts only canonical slugs for section-route resolution. Method NormalizeKey string NormalizeKey ( string? value ) Normalizes authored section metadata so labels, slugs, and aliases can share one lookup table. Parameters value The authored value to normalize. Returns A lowercase alphanumeric key, or an empty string when value is blank. Method NormalizeSlug string NormalizeSlug ( string? value ) Normalizes an incoming section-route slug while preserving the canonical hyphenated slug contract. Parameters value The incoming route slug. Returns The trimmed lowercase slug, or an empty string when value is blank. Property OrderedSections IReadOnlyList\u003CDocPublicSection\u003E OrderedSections { get; } Gets the public sections in their intended presentation order for docs home and sidebar surfaces. Type Definition Describes one built-in public section, including its canonical display label, stable route slug, and accepted aliases.","snippet":"Type DocPageTypeBadgePresentation Presentation metadata for one normalized documentation page-type badge. Property Value string Value { get; init; } Gets the normalized machine-readable page-type value. Property Label...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocBreadcrumbViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocBreadcrumbViewModel","title":"DocBreadcrumbViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocBreadcrumbViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocBreadcrumbViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocContributorMetadata","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocContributorMetadata","title":"DocContributorMetadata","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocContributorMetadata"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocContributorMetadata"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocContributorProvenanceViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocContributorProvenanceViewModel","title":"DocContributorProvenanceViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocContributorProvenanceViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocContributorProvenanceViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocDetailsViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocDetailsViewModel","title":"DocDetailsViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocDetailsViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocDetailsViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocFeaturedPageDefinition","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocFeaturedPageDefinition","title":"DocFeaturedPageDefinition","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocFeaturedPageDefinition"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocFeaturedPageDefinition"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocFeaturedPageGroupDefinition","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocFeaturedPageGroupDefinition","title":"DocFeaturedPageGroupDefinition","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocFeaturedPageGroupDefinition"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocFeaturedPageGroupDefinition"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnostic","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnostic","title":"DocHarvestDiagnostic","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvestDiagnostic"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnostic"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnosticCodes","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnosticCodes","title":"DocHarvestDiagnosticCodes","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvestDiagnosticCodes"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnosticCodes"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnosticSeverity","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnosticSeverity","title":"DocHarvestDiagnosticSeverity","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvestDiagnosticSeverity"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvestDiagnosticSeverity"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvesterHealth","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvesterHealth","title":"DocHarvesterHealth","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvesterHealth"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvesterHealth"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvesterHealthStatus","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvesterHealthStatus","title":"DocHarvesterHealthStatus","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvesterHealthStatus"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvesterHealthStatus"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestFailureDiagnostic","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestFailureDiagnostic","title":"DocHarvestFailureDiagnostic","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvestFailureDiagnostic"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvestFailureDiagnostic"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestFailureSummary","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestFailureSummary","title":"DocHarvestFailureSummary","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvestFailureSummary"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvestFailureSummary"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestHealthSnapshot","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestHealthSnapshot","title":"DocHarvestHealthSnapshot","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvestHealthSnapshot"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvestHealthSnapshot"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestHealthStatus","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHarvestHealthStatus","title":"DocHarvestHealthStatus","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHarvestHealthStatus"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHarvestHealthStatus"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHomeSectionViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocHomeSectionViewModel","title":"DocHomeSectionViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocHomeSectionViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocHomeSectionViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocLandingFeaturedPageGroupViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocLandingFeaturedPageGroupViewModel","title":"DocLandingFeaturedPageGroupViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocLandingFeaturedPageGroupViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocLandingFeaturedPageGroupViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocLandingFeaturedPageViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocLandingFeaturedPageViewModel","title":"DocLandingFeaturedPageViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocLandingFeaturedPageViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocLandingFeaturedPageViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocLandingViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocLandingViewModel","title":"DocLandingViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocLandingViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocLandingViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocMetadata","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocMetadata","title":"DocMetadata","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocMetadata"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocMetadata"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocMetadataPresentation","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocMetadataPresentation","title":"DocMetadataPresentation","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocMetadataPresentation"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocMetadataPresentation"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocNode","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocNode","title":"DocNode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocNode"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocNode"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocOutlineItem","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocOutlineItem","title":"DocOutlineItem","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocOutlineItem"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocOutlineItem"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPageLinkViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPageLinkViewModel","title":"DocPageLinkViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocPageLinkViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocPageLinkViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPageTypeBadgePresentation","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPageTypeBadgePresentation","title":"DocPageTypeBadgePresentation","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocPageTypeBadgePresentation"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocPageTypeBadgePresentation"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPublicSection","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPublicSection","title":"DocPublicSection","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocPublicSection"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocPublicSection"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPublicSectionCatalog","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPublicSectionCatalog","title":"DocPublicSectionCatalog","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocPublicSectionCatalog"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocPublicSectionCatalog"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPublicSectionCatalog-Definition","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocPublicSectionCatalog-Definition","title":"Definition","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","Definition"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocPublicSectionCatalog-Definition"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionGroupViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionGroupViewModel","title":"DocSectionGroupViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSectionGroupViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSectionGroupViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionLinkViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionLinkViewModel","title":"DocSectionLinkViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSectionLinkViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSectionLinkViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionPageViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionPageViewModel","title":"DocSectionPageViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSectionPageViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSectionPageViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionSnapshot","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSectionSnapshot","title":"DocSectionSnapshot","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSectionSnapshot"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSectionSnapshot"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSidebarHarvestHealthViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSidebarHarvestHealthViewModel","title":"DocSidebarHarvestHealthViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSidebarHarvestHealthViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSidebarHarvestHealthViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSidebarSectionViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSidebarSectionViewModel","title":"DocSidebarSectionViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSidebarSectionViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSidebarSectionViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSidebarViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSidebarViewModel","title":"DocSidebarViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSidebarViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSidebarViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSymbolSourceProvenance","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocSymbolSourceProvenance","title":"DocSymbolSourceProvenance","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocSymbolSourceProvenance"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocSymbolSourceProvenance"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocTrustLink","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocTrustLink","title":"DocTrustLink","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocTrustLink"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocTrustLink"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocTrustMetadata","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-DocTrustMetadata","title":"DocTrustMetadata","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","DocTrustMetadata"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-DocTrustMetadata"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-IDocHarvester","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-IDocHarvester","title":"IDocHarvester","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","IDocHarvester"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-IDocHarvester"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestDiagnosticResponse","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestDiagnosticResponse","title":"RazorDocsHarvestDiagnosticResponse","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","RazorDocsHarvestDiagnosticResponse"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestDiagnosticResponse"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvesterHealthResponse","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvesterHealthResponse","title":"RazorDocsHarvesterHealthResponse","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","RazorDocsHarvesterHealthResponse"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvesterHealthResponse"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestFailedException","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestFailedException","title":"RazorDocsHarvestFailedException","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","RazorDocsHarvestFailedException"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestFailedException"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestHealthResponse","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestHealthResponse","title":"RazorDocsHarvestHealthResponse","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","RazorDocsHarvestHealthResponse"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestHealthResponse"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestHealthVerification","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestHealthVerification","title":"RazorDocsHarvestHealthVerification","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","RazorDocsHarvestHealthVerification"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-RazorDocsHarvestHealthVerification"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsVersionArchiveEntryViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsVersionArchiveEntryViewModel","title":"RazorDocsVersionArchiveEntryViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","RazorDocsVersionArchiveEntryViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-RazorDocsVersionArchiveEntryViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsVersionArchiveViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-RazorDocsVersionArchiveViewModel","title":"RazorDocsVersionArchiveViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","RazorDocsVersionArchiveViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-RazorDocsVersionArchiveViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-SearchPageFallbackLink","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-SearchPageFallbackLink","title":"SearchPageFallbackLink","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","SearchPageFallbackLink"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-SearchPageFallbackLink"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-SearchPageViewModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Models.html#ForgeTrust-AppSurface-Docs-Models-SearchPageViewModel","title":"SearchPageViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Models","SearchPageViewModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Models#ForgeTrust-AppSurface-Docs-Models-SearchPageViewModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html","title":"Services","summary":"Type CSharpDocHarvester Harvester implementation that scans C# source files for XML documentation comments. Method HarvestAsync Task\u003CIReadOnlyList\u003CDocNode\u003E\u003E HarvestAsync ( string rootPath , CancellationToken...","headings":["CSharpDocHarvester","HarvestAsync","GetMethodId","GetPropertyId","GetHighlightedDisplaySignature","GetHighlightedPropertySignature","GetPropertyAccessorSignature","AppendHighlightedParameter","GetDisplayTypeName","GetTypeNameForQualifiedId","IsCompilerGeneratedCallerParameter","ExtractDoc","AppendTextSection","AppendNamedListSection","RenderBlockContent","RenderInlineContent","RenderNodes","RenderNode","NormalizeWhitespace","AddOutlineItem","SimplifyCref","IsCompilerGeneratedDocParameter","GetOrCreateNamespacePage","EnsureNamespaceHierarchy"],"bodyText":"Type CSharpDocHarvester Harvester implementation that scans C# source files for XML documentation comments. Method HarvestAsync Task\u003CIReadOnlyList\u003CDocNode\u003E\u003E HarvestAsync ( string rootPath , CancellationToken cancellationToken = default ) Collects XML documentation from C# source files under the specified root and produces DocNode entries containing titles, relative file paths with anchors, and HTML-formatted content. Parameters rootPath The root directory to recursively scan for .cs files. cancellationToken An optional token to observe for cancellation requests. Returns A collection of DocNode objects; each contains a title, a relative file path including a fragment anchor, and the extracted HTML documentation. Remarks Skips files in excluded directories (for example \u0022node_modules\u0022, \u0022bin\u0022, \u0022obj\u0022, \u0022Tests\u0022, and \u0022examples\u0022) and hidden dot-prefixed directories unless explicitly allowlisted. Dot-prefixed files are included. Method GetMethodId string GetMethodId ( MethodDeclarationSyntax method , string qualifiedTypeName ) Computes the safe ID for a method to be used in HTML content and stub nodes. Parameters method The method declaration syntax. qualifiedTypeName The qualified name of the containing type. Returns The safe ID string for the method documentation section. Method GetPropertyId string GetPropertyId ( PropertyDeclarationSyntax property , string qualifiedTypeName ) Computes the safe ID for a property to be used in HTML content and stub nodes. Parameters property The property declaration syntax. qualifiedTypeName The qualified name of the containing type. Returns The safe ID string for the property documentation section. Method GetHighlightedDisplaySignature string GetHighlightedDisplaySignature ( MethodDeclarationSyntax method ) Generates a syntax-highlighted HTML string representing a method signature for display. Parameters method The method declaration syntax. Returns An HTML fragment containing the highlighted signature. Method GetHighlightedPropertySignature string GetHighlightedPropertySignature ( PropertyDeclarationSyntax property ) Generates a syntax-highlighted HTML string representing a property signature for display. Parameters property The property declaration syntax. Returns An HTML fragment containing the highlighted signature. Method GetPropertyAccessorSignature string GetPropertyAccessorSignature ( PropertyDeclarationSyntax property ) Computes the accessors (get/set/init) for a property as a string for inclusion in signatures. Parameters property The property declaration syntax. Returns A string like \u0022{ get; set; }\u0022 or \u0022{ get; }\u0022. Method AppendHighlightedParameter void AppendHighlightedParameter ( StringBuilder builder , ParameterSyntax parameter ) Appends a syntax-highlighted parameter declaration to the provided StringBuilder. Parameters builder The StringBuilder to append to. parameter The parameter declaration syntax. Method GetDisplayTypeName string GetDisplayTypeName ( TypeDeclarationSyntax typeDecl ) Gets the display name for a type declaration, including generic type parameter placeholders (e.g., \u003CT\u003E). Parameters typeDecl The type declaration syntax. Returns The display name string. Method GetTypeNameForQualifiedId string GetTypeNameForQualifiedId ( TypeDeclarationSyntax typeDecl ) Gets the type name for a qualified ID, appending backtick arity for generic types (e.g., MyType\u00601). Parameters typeDecl The type declaration syntax. Returns The type name string used in safe IDs. Method IsCompilerGeneratedCallerParameter bool IsCompilerGeneratedCallerParameter ( ParameterSyntax parameter ) Determines whether a parameter is a compiler-generated caller information parameter (e.g., [CallerFilePath]). Parameters parameter The parameter declaration syntax. Returns true if the parameter should be hidden from documentation; otherwise, false . Method ExtractDoc string? ExtractDoc ( SyntaxNode node ) Extracts XML documentation from the leading trivia of a syntax node and converts it into HTML fragments. Parameters node The syntax node whose leading XML documentation comments will be parsed. Returns The HTML string containing structured documentation sections, or null if no documentation is present or parsing fails. Method AppendTextSection void AppendTextSection ( StringBuilder html , string cssClass , XElement? section , string? heading = null ) Appends a simple text section (like summary or remarks) to the HTML builder. Parameters html The StringBuilder to append to. cssClass The CSS class name for the section container. section The XElement containing the documentation section. heading Optional heading text for the section. Method AppendNamedListSection void AppendNamedListSection ( StringBuilder html , string cssClass , string heading , IEnumerable\u003CXElement\u003E entries , Func\u003CXElement, string?\u003E keySelector ) Appends a list of named entries (like parameters or exceptions) to the HTML builder. Parameters html The StringBuilder to append to. cssClass The CSS class name for the section container. heading The heading text for the section. entries The collection of XElements to process. keySelector A function that extracts the name or key for each entry. Method RenderBlockContent string RenderBlockContent ( XElement element ) Renders the content of an XElement as block-level HTML (wrapping in paragraphs if necessary). Parameters element The XElement to render. Returns An HTML fragment string. Method RenderInlineContent string RenderInlineContent ( XElement element ) Renders the content of an XElement as inline HTML. Parameters element The XElement to render. Returns An HTML fragment string. Method RenderNodes string RenderNodes ( IEnumerable\u003CXNode\u003E nodes , bool inlineContext ) Renders a collection of XML nodes into HTML strings. Parameters nodes The nodes to render. inlineContext Indicates whether rendering occurs in an inline context (affects paragraph handling). Returns The combined HTML string. Method RenderNode string RenderNode ( XNode node , bool inlineContext ) Renders a single XML node into its corresponding HTML fragment. Parameters node The node to render. inlineContext Indicates whether rendering occurs in an inline context. Returns The HTML fragment string. Method NormalizeWhitespace string NormalizeWhitespace ( string value ) Normalizes whitespace in the provided string by replacing all whitespace sequences with a single space. Parameters value The string to normalize. Returns The normalized string. Method AddOutlineItem void AddOutlineItem ( NamespaceDocPage namespacePage , string title , string id , int level ) Adds an outline item to a namespace page when the entry is complete and its target ID has not already been recorded. Parameters namespacePage The namespace page receiving the outline item. title The reader-facing outline title. id The fragment identifier for the rendered documentation section. level The normalized outline level. Method SimplifyCref string? SimplifyCref ( string? cref ) Simplifies a \u0022cref\u0022 attribute value by removing the type prefix (e.g., \u0022M:\u0022, \u0022T:\u0022). Parameters cref The cref value to simplify. Returns The simplified string, or null if the input was empty. Method IsCompilerGeneratedDocParameter bool IsCompilerGeneratedDocParameter ( string? parameterName ) Determines whether a parameter name corresponds to a compiler-generated caller information parameter. Parameters parameterName The name of the parameter to check. Returns true if it is a compiler-generated parameter; otherwise, false . Method GetOrCreateNamespacePage NamespaceDocPage GetOrCreateNamespacePage ( IDictionary\u003Cstring, NamespaceDocPage\u003E namespacePages , string namespaceName ) Gets an existing NamespaceDocPage for the specified namespace name, or creates a new one if it doesn\u0027t exist. Parameters namespacePages The dictionary of existing pages. namespaceName The dotted namespace name. Returns The retrieved or newly created page. Method EnsureNamespaceHierarchy void EnsureNamespaceHierarchy ( IDictionary\u003Cstring, NamespaceDocPage\u003E namespacePages ) Builds the hierarchical structure for namespaces, ensuring parent pages exist and child links are added back into the content. Rebuilds namespacePages in place keyed by NamespaceDocPage.Path . Parameters namespacePages The dictionary containing all unique namespace pages encountered during harvesting. Method GetNamespaceName string GetNamespaceName ( SyntaxNode node ) Extracts the dotted namespace name for a given syntax node by traversing its ancestors. Parameters node The syntax node to process. Returns The full dotted namespace name, or \u0022Global\u0022 if none is found. Method BuildNamespaceDocPath string BuildNamespaceDocPath ( string namespaceName ) Constructs the relative documentation route path for a given namespace name. Parameters namespaceName The dotted namespace name. Returns The relative route path string (e.g., \u0022Namespaces/MyNamespace\u0022). Method GetNamespaceTitle string GetNamespaceTitle ( string fullNamespace ) Derives a display title for a namespace name. Parameters fullNamespace The dotted namespace name. Returns The display title; returns the last segment of the namespace or \u0022Namespaces\u0022 for the root. Method GetParentNamespace string GetParentNamespace ( string namespaceName ) Gets the parent namespace name for a dotted namespace string. Parameters namespaceName The dotted namespace name. Returns The parent namespace name, or an empty string if it is a root namespace. Method GetQualifiedName string GetQualifiedName ( BaseTypeDeclarationSyntax node ) Builds the dot-delimited qualified name for a type or enum declaration, including enclosing types and namespaces. Parameters node The type or enum declaration syntax node to compute the qualified name for. Returns The qualified name as a dot-delimited string containing nested type and namespace segments. Type NamespaceDocPage Represents a single documentation page for a C# namespace, accumulating content from types within it. Type DocRouteIdentityCatalog Owns the route identity contract for one cached RazorDocs snapshot. Remarks The catalog deliberately separates source identity from public route identity: source path -\u003E internal lookup and authoring provenance public route path -\u003E browser-facing canonical URL redirect alias -\u003E declared or Markdown source-shaped URL that redirects to public route Controllers render only public canonical winners. Declared aliases and Markdown source-shaped paths for public winners redirect to the canonical route, while non-Markdown source paths, collision losers, and reserved routes stay non-public. Link builders can still resolve source paths so authored Markdown stays source-friendly without rendering source-shaped URLs into the reader-facing surface. Type DocMetadataFactory Builds normalized RazorDocs metadata defaults and fallbacks for harvested documentation nodes. Method CreateMarkdownMetadata 2 overloads DocMetadata CreateMarkdownMetadata ( string path , string resolvedTitle , DocMetadata? explicitMetadata , string? derivedSummary ) Creates normalized metadata for a Markdown documentation node without emitting normalization warnings. Parameters path The source path used for default section, page-type, and audience inference. resolvedTitle The resolved display title for the Markdown node. explicitMetadata Optional authored metadata that should override inferred defaults. derivedSummary Optional summary text derived from the document body. Returns The merged metadata with inferred defaults, normalized nav-group handling, and fallback breadcrumbs. DocMetadata CreateMarkdownMetadata ( string path , string resolvedTitle , DocMetadata? explicitMetadata , string? derivedSummary , ILogger? logger ) Creates normalized metadata for a Markdown documentation node and optionally logs authored nav-group fallback warnings. Parameters path The source path used for default section, page-type, and audience inference. resolvedTitle The resolved display title for the Markdown node. explicitMetadata Optional authored metadata that should override inferred defaults. derivedSummary Optional summary text derived from the document body. logger An optional logger that receives warnings when authored nav_group values do not resolve to a built-in public section and RazorDocs falls back to the derived section assignment. Returns The merged metadata with normalized section labels, fallback breadcrumbs, and derived-field flags. Remarks This shared internal entry point normalizes explicit public-section selection, preserves authored metadata where valid, derives title/summary fallback semantics, and rebuilds default breadcrumbs when authors do not supply them explicitly. Method CreateApiReferenceMetadata DocMetadata CreateApiReferenceMetadata ( string title , string namespaceName ) Creates canonical metadata for an API-reference documentation node. Parameters title The display title for the API node. namespaceName The owning namespace used for component inference and breadcrumb generation. Returns Metadata configured for API-reference navigation, contributor visibility, and namespace breadcrumbs. Method DeriveComponentFromPath string? DeriveComponentFromPath ( string path ) Derives the owning AppSurface component name from a documentation path when possible. Parameters path The documentation path whose segments should be inspected. Returns The inferred component name, or null when no component hint can be derived. Method DeriveComponentFromNamespace string? DeriveComponentFromNamespace ( string namespaceName ) Derives the owning AppSurface component name from a namespace. Parameters namespaceName The namespace to inspect. Returns The inferred component name, or null when the namespace is blank. Type HarvestPathExclusions Method ShouldExcludeFilePath 2 overloads bool ShouldExcludeFilePath ( string filePath ) Determines whether a documentation file should be excluded from harvesting based on its path segments. Parameters filePath The relative file path to check. Returns true if the file should be excluded; otherwise, false . bool ShouldExcludeFilePath ( string filePath , IReadOnlySet\u003Cstring\u003E excludedDirectories , bool excludeTestProjectDirectories = false ) Determines whether a file should be excluded based on shared hidden-directory rules and a caller-supplied set of explicitly excluded directory names. Parameters filePath The relative file path to check. excludedDirectories Directory names that should always be excluded in addition to the shared hidden-directory behavior. excludeTestProjectDirectories When true , also excludes test-project directory segments by case-insensitive exact names ( Test , Tests , UnitTests , IntegrationTests , FunctionalTests , E2ETests ) and case-insensitive suffix patterns ( *.Tests , *.UnitTests , *.IntegrationTests , *.FunctionalTests , *.E2ETests , *-Tests , and *_Tests ). Returns true if the file should be excluded; otherwise, false . Type RazorDocsCodeBlock Represents the authored Markdown code-fence input that RazorDocs can render as highlighted or plain code. Parameters Code The literal code block body, or null when an upstream renderer provides no text. Language The first whitespace-delimited Markdown info-string token, or null when omitted. Remarks RazorDocsCodeBlock stores only the first whitespace-delimited info-string token in Language because the renderer treats that token as the language hint. It does not parse full info-string attributes. Language may be null when the info string is omitted, and Code may be null when an upstream renderer provides no text, so callers must handle both defensively. Type IRazorDocsCodeHighlighter Highlights Markdown code fences behind RazorDocs\u0027 internal HTML contract. Method Highlight RazorDocsHighlightedCode Highlight ( RazorDocsCodeBlock block ) Renders a code block as either highlighted token markup or escaped plaintext fallback. Parameters block The code block to render. Returns RazorDocs-owned code block HTML. Type DocPathResolver Resolves authored, source, and canonical RazorDocs paths against a harvested documentation corpus. Remarks RazorDocs accepts paths from several authoring surfaces: browser routes, source-relative Markdown metadata, generated canonical paths, and route-prefixed links. This resolver is the shared source of truth for trimming route separators, ignoring lookup fragments when selecting candidate buckets, preserving exact fragment matches when available, and ranking fallback candidates when a fragment-specific page is not present. Method Create DocPathResolver Create ( IEnumerable\u003CDocNode\u003E docs ) Builds a resolver for a docs snapshot. Parameters docs The harvested docs whose source and canonical paths should be resolvable. Returns A resolver that can match source paths, canonical route paths, and route-relative variants. Method Resolve 2 overloads DocNode? Resolve ( string path ) Resolves a path exactly as authored, using RazorDocs source and canonical matching rules. Parameters path The authored source or canonical path to resolve. Returns The best matching doc node, or null when no harvested doc matches. DocNode? Resolve ( string path , params string[] routeRootPaths ) Resolves a path by preserving authored source-relative matches before stripping known docs route roots from browser-facing inputs. Parameters path The authored or browser-facing path to resolve. routeRootPaths Route roots, such as the configured live docs root and the stable /docs root. Returns The best matching doc node, or null when neither route-relative variants nor the original path match. Method NormalizeLookupPath string NormalizeLookupPath ( string path ) Normalizes a documentation path for lookup by trimming route separators and removing fragment anchors. Parameters path The path to normalize. Returns The normalized lookup path. Method NormalizeCanonicalPath string NormalizeCanonicalPath ( string path ) Normalizes a documentation path for canonical comparison by trimming route separators while preserving fragments. Parameters path The path to normalize. Returns The normalized canonical path. Method GetFragment string? GetFragment ( string path ) Extracts a fragment from a documentation path after canonical normalization. Parameters path The path that may contain a fragment anchor. Returns The fragment without the leading # , or null when no non-empty fragment exists. Type RazorDocsHeadingSuppressor Applies page-shell heading rules to harvested documentation HTML at render time. Method SuppressLeadingMarkdownH1 string SuppressLeadingMarkdownH1 ( string content , bool shellOwnsH1 ) Removes the leading rendered Markdown h1 element when the details page shell already renders the page H1. Parameters content The sanitized harvested HTML body to render inside the details page content surface. shellOwnsH1 true when the page shell renders the semantic H1 from Models.DocDetailsViewModel.Title ; false when the harvested body remains responsible for its own top-level heading. Returns The original content when the shell does not own the H1 or when the body does not begin with an h1 ; otherwise the body with that first rendered h1 removed. Remarks Only the leading H1 is suppressed. Later H1 elements remain visible because they are authored body structure, not duplicated page chrome. Type RazorDocsVersionCatalogService Loads, validates, and resolves the configured RazorDocs version catalog. Remarks The service performs best-effort validation so a broken stored release tree becomes unavailable without preventing healthy versions or the live preview surface from loading. Validation is intentionally release-local: every version is checked independently for a readable tree root, the required landing and search pages, the search index, and the shared search runtime assets that exact-version pages depend on. Exact trees are otherwise treated as immutable, self-contained artifacts: outline-aware exports should include the page-local outline runtime they reference, while historical trees are not crawled or upgraded at host startup. Public RazorDocsResolvedVersion.AvailabilityIssue values are sanitized for archive UI consumption, while filesystem paths and exception details stay in structured logs only. Method GetCatalog RazorDocsResolvedVersionCatalog GetCatalog () Returns the resolved version catalog for the current host. Returns The resolved catalog including availability information for each published version. Returns RazorDocsResolvedVersionCatalog.Disabled when versioning is off for this host, RazorDocsResolvedVersionCatalog.EnabledWithoutCatalog when versioning is on but no catalog path was configured, and RazorDocsResolvedVersionCatalog.CreateUnavailable(string?) semantics when a configured catalog could not be loaded into a usable published-release set. Type RazorDocsResolvedVersionCatalog Represents the resolved version catalog used by the current host. Parameters Status The high-level catalog resolution state for the current host. This distinguishes successful resolution from the three sentinel states where versioning is disabled, missing a catalog path, or configured but unavailable. CatalogPath The catalog path associated with the resolved state. This stays null for the Disabled and EnabledWithoutCatalog sentinels, is typically an absolute filesystem path after successful resolution or file-based unavailability checks, and can remain the normalized configured value when Status is RazorDocsResolvedVersionCatalogStatus.Unavailable because absolute resolution failed before CreateUnavailable(string?) was created. Versions The resolved catalog entries in authored catalog order. Entries stay present even when a published tree is unavailable so archive, diagnostics, and fallback experiences can explain the broken release instead of silently hiding it. RecommendedVersion The resolved recommended version when one is public and available. This can be null when versioning is disabled, no recommendation was configured, the configured identifier did not resolve, or the matching release was hidden or unavailable after validation. Remarks Disabled means the host is running with versioning off, so callers should treat the live docs surface as the only public experience and skip published-release archive UI entirely. EnabledWithoutCatalog means versioning was turned on but no catalog path was configured, so callers can still expose the live preview surface but should not expect any published releases to resolve. PublicVersions preserves the ordering from Versions after filtering by RazorDocsVersionVisibility.Public only. Public-but-unavailable releases remain in that list so the archive can surface their degraded status instead of pretending they do not exist. Method CreateUnavailable RazorDocsResolvedVersionCatalog CreateUnavailable ( string? catalogPath ) Creates an enabled catalog result with no available versions because the backing catalog could not be used. Parameters catalogPath The resolved catalog path to surface with the unavailable sentinel. This is usually an absolute filesystem path, but can also be the normalized configured value when resolution failed before an absolute path could be constructed. Returns An enabled-but-unavailable catalog result. Property Disabled RazorDocsResolvedVersionCatalog Disabled { get; } Gets the sentinel catalog result for hosts where versioning is disabled entirely. Property EnabledWithoutCatalog RazorDocsResolvedVersionCatalog EnabledWithoutCatalog { get; } Gets the sentinel catalog result for hosts where versioning is enabled but no catalog path was configured. Property PublicVersions IReadOnlyList\u003CRazorDocsResolvedVersion\u003E PublicVersions { get; } Gets the public versions that should appear in the archive. Remarks This list preserves the authored order from Versions after filtering only by RazorDocsVersionVisibility.Public . Versions stay in the list even when RazorDocsResolvedVersion.IsAvailable is false so archive consumers can show degraded-release messaging instead of silently dropping known public releases. Type RazorDocsResolvedVersion Represents one resolved published docs version and its runtime availability. Parameters Version The exact published version identifier. Label The archive label shown to readers. Summary Optional summary copy shown in the archive. ExactTreePath The resolved absolute path to the exported exact-version subtree. ExactRootUrl The canonical public root URL for the exact version. SupportState The support-state badge surfaced in the archive. Visibility The archive visibility state. AdvisoryState The release-level advisory state. IsAvailable Whether the exact-version tree validated successfully. AvailabilityIssue The sanitized public-facing availability explanation when the tree is unavailable. Internal logs retain filesystem paths and exception details, but this message is safe to surface in archive UI and reader-facing diagnostics. Enum RazorDocsResolvedVersionCatalogStatus Describes how the current host resolved its published-version catalog state. Remarks Numeric values are explicit and stable because callers may serialize or persist catalog-resolution state across process boundaries. Type RazorDocsPublishedTreeHandler Serves one or more published RazorDocs trees from static export artifacts. Remarks Published trees are usually exported from the stable /docs surface and then mounted later under the configured route-family root or {RouteRootPath}/v/{version} . This handler resolves extensionless requests back to the exporter\u2019s .html files and rewrites stable-root HTML or search-index payloads so the mounted tree stays version-local. Method TryHandleAsync Task\u003Cbool\u003E TryHandleAsync ( HttpContext httpContext ) Attempts to serve the current request from one of the configured published trees. Parameters httpContext The current HTTP request context. Returns true when a published tree handled the request; otherwise false . Type RazorDocsPublishedTreeMount Describes one published exact-version tree that should be mounted into the active host. Parameters MountRootPath The request-path root where the tree should appear. FileProvider The static file provider for the tree contents. Remarks When multiple RazorDocsPublishedTreeMount instances overlap, callers should treat the longest MountRootPath as the winning mount because the request handler resolves mounts from most-specific to least-specific roots before serving content. Type RazorDocsPublishedTreeContentRewriter Rewrites stable-root published-tree content so the same artifact can be served from different mount roots. Remarks Rewrites are mount-aware rather than file-aware. The active RazorDocsPublishedTreeMount decides which root wins, and then the rewriter adjusts exported stable-root URLs so they point at that mounted surface. The default stable /docs surface only needs HTML rewrites when the host adds a non-empty request PathBase ; when the mount root and route root are still /docs and no PathBase applies, the exported HTML is already correct and is returned unchanged. Method RewriteHtml string RewriteHtml ( string html , string mountRootPath , string previewRootPath = \u0022/docs/next\u0022 , string routeRootPath = DocsUrlBuilder.DocsEntryPath , string? requestPathBase = null ) Rewrites stable-root HTML so docs-local links, assets, and client config point at the supplied mount root. Parameters html The exported HTML document. mountRootPath The request-path root where the tree is being served. previewRootPath The live preview docs root that should stay untouched when encountered. routeRootPath The route-family root that owns archive and exact-version routes. requestPathBase The current host path base that should prefix rewritten app-relative docs URLs. Returns The rewritten HTML document. Remarks This method rewrites exported stable-root docs links, assets, and the inline window.__razorDocsConfig payload matched by DocsClientConfigRegex so the document behaves like it was originally emitted for mountRootPath . As part of that rewrite, the legacy docsVersionsUrl client field is removed because version archive navigation is rendered server-side. When mountRootPath and routeRootPath are both the default /docs , rewrites only occur if requestPathBase is non-empty so sub-path-hosted apps still emit /some-base/docs/... links. Method RewriteSearchIndexJson string RewriteSearchIndexJson ( string json , string mountRootPath , string previewRootPath = \u0022/docs/next\u0022 , string routeRootPath = DocsUrlBuilder.DocsEntryPath , string? requestPathBase = null ) Rewrites a published search-index payload so mounted document URLs stay inside the active docs surface. Parameters json The exported search-index payload. mountRootPath The request-path root where the tree is being served. previewRootPath The live preview docs root that should stay untouched when encountered. routeRootPath The route-family root that owns archive and exact-version routes. requestPathBase The current host path base that should prefix rewritten app-relative docs URLs. Returns The original payload when the mount and route root are the default /docs surface without a non-empty path base, when the payload is not a JSON object with a top-level documents array, or when no eligible documents[*].path values require rewriting; otherwise a payload whose rewritten document paths stay inside the mounted docs root. Remarks Only documents[*].path values are rewritten. Other JSON fields, including titles, metadata, and facet payloads, are preserved exactly as exported. Default stable mounts rooted at /docs are a no-op unless requestPathBase is non-empty, because the exported payload already points at the default surface. Preview-root paths, archive paths such as {RouteRootPath}/versions , and already-versioned exact routes such as {RouteRootPath}/v/1.2.3/guide.html are preserved rather than rebased. When a rewrite does occur, the helper prepends the normalized request path base to eligible app-relative URLs, so /docs/guide.html becomes /some-base/docs/v/1.2.3/guide.html for an exact mount at /docs/v/1.2.3 . Callers should not expect other JSON fields to change, and they must supply a non-empty requestPathBase if stable mounts need virtual-directory rebasing. Type MarkdownFrontMatterParser Method Extract (string Markdown, DocMetadata? Metadata) Extract ( string markdown ) Extracts inline Markdown front matter and returns the remaining Markdown with parsed metadata. Parameters markdown The Markdown source that may begin with YAML front matter. Returns A tuple containing the Markdown body and parsed DocMetadata when present and valid. Remarks This compatibility wrapper discards parser diagnostics. Invalid inline YAML returns the original Markdown with null metadata, and non-fatal authoring warnings such as invalid curation YAML or migration metadata are intentionally not surfaced. Call ExtractWithDiagnostics when callers need warnings. Method ExtractWithDiagnostics (string Markdown, MarkdownMetadataParseResult Result) ExtractWithDiagnostics ( string markdown ) Extracts inline Markdown front matter and returns the remaining Markdown with diagnostics-aware metadata. Parameters markdown The Markdown source that may begin with YAML front matter. Returns A tuple containing the Markdown body and a MarkdownMetadataParseResult whose MarkdownMetadataParseResult.Metadata contains parsed DocMetadata when present. Remarks This is the authoritative internal entry point for inline metadata parsing. Missing front matter returns the original Markdown and an empty diagnostic list. Invalid inline YAML returns a RazorDocsMetadataDiagnostic instead of throwing, and deliberately preserves the original Markdown so a malformed header remains visible to the reader. Callers should inspect MarkdownMetadataParseResult.Diagnostics for authoring warnings instead of relying on exceptions for inline metadata failures. Method ParseMetadataYaml DocMetadata? ParseMetadataYaml ( string yaml ) Parses a YAML metadata document into normalized documentation metadata. Parameters yaml The raw YAML content to deserialize. Returns The normalized metadata model, or null when the YAML document is empty or explicitly null. Exceptions YamlException Thrown when yaml cannot be parsed as YAML. Remarks This compatibility wrapper is shared by inline Markdown front matter and paired sidecar metadata files so both authoring styles normalize through the same schema, defaults, and empty-list handling. It returns only the MarkdownMetadataParseResult.Metadata value from ParseMetadataYamlWithDiagnostics(string) and intentionally discards schema, migration, and authoring diagnostics. Call ParseMetadataYamlWithDiagnostics(string) when callers need those warnings in addition to normalized DocMetadata . Method ParseMetadataYamlWithDiagnostics MarkdownMetadataParseResult ParseMetadataYamlWithDiagnostics ( string yaml ) Parses a YAML metadata document into a diagnostics-aware metadata result. Parameters yaml The raw YAML metadata document to deserialize. Returns A MarkdownMetadataParseResult containing optional normalized DocMetadata plus any RazorDocsMetadataDiagnostic warnings produced while normalizing supported metadata fields. Remarks This is the authoritative internal entry point for metadata documents that are already known to be YAML, including sidecar files. Empty documents and explicit YAML null values return null metadata and no diagnostics. An empty mapping literal such as {} still produces a normalized DocMetadata instance whose fields may all be null . YAML syntax errors still throw YamlException so sidecar callers can report the sidecar file failure through their existing error path; schema and migration warnings are returned through MarkdownMetadataParseResult.Diagnostics . Type RazorDocsHarvestFailurePreflightService Performs the optional strict RazorDocs harvest-health startup preflight. Remarks The service is always registered by AddRazorDocs() , but it is inert unless RazorDocsHarvestOptions.FailOnFailure is enabled. Strict mode reads DocAggregator.GetHarvestHealthAsync(CancellationToken) so startup observes the same cached snapshot that docs requests use instead of running a second harvest pipeline. Method StartAsync Task StartAsync ( CancellationToken cancellationToken ) Checks harvest health during host startup when strict harvest failure is enabled. Parameters cancellationToken Token observed while waiting for the cached harvest-health snapshot. Returns A completed task when strict mode is disabled or the aggregate status is not failed. Exceptions RazorDocsHarvestFailedException Thrown when RazorDocsHarvestOptions.FailOnFailure is enabled and the aggregate harvest status is DocHarvestHealthStatus.Failed . Method StopAsync Task StopAsync ( CancellationToken cancellationToken ) Stops the preflight service. Parameters cancellationToken Unused cancellation token supplied by the host. Returns A completed task because the preflight owns no background work. Type RazorDocsHarvestHealthVisibility Resolves environment-aware visibility for RazorDocs harvest health routes and sidebar chrome. Method AreRoutesExposed bool AreRoutesExposed ( RazorDocsOptions options , IHostEnvironment environment ) Resolves whether the harvest health controller routes should be registered or allowed for the current host. Remarks This internal helper uses RazorDocsOptions.Harvest health route settings and the supplied host environment. Missing health options fall back to RazorDocsHarvestHealthExposure.DevelopmentOnly . Callers must pass the real host environment; the method null-checks both arguments before applying the environment-gated visibility contract. Method ShouldShowChrome bool ShouldShowChrome ( RazorDocsOptions options , IHostEnvironment environment ) Resolves whether the sidebar should show harvest health chrome for the current host. Remarks This internal helper uses RazorDocsOptions.Harvest health chrome settings and the supplied host environment. Missing health options fall back to RazorDocsHarvestHealthExposure.DevelopmentOnly . Callers use this for presentation chrome only; route exposure is resolved separately by AreRoutesExposed(RazorDocsOptions, IHostEnvironment) . The method null-checks both arguments before applying the environment-gated visibility contract. Type RazorDocsCodeBlockMarkdownExtension Registers RazorDocs\u0027 fenced-code renderer with Markdig. Method CreateDefaultHighlighter IRazorDocsCodeHighlighter CreateDefaultHighlighter ( ILogger\u003CTextMateSharpRazorDocsCodeHighlighter\u003E logger ) Creates the default TextMateSharp-backed RazorDocs highlighter. Parameters logger Logger used to emit diagnostics when grammar loading or highlighting falls back. Returns The default RazorDocs code highlighter. Type RazorDocsCodeBlockRenderer Renders Markdown fenced code blocks through RazorDocs\u0027 highlighter contract. Method ExtractLanguage string? ExtractLanguage ( FencedCodeBlock block ) Extracts the first language token from a fenced code block\u0027s info string. Parameters block The fenced code block to inspect. Returns The first language token, or null when the fence has no info string. Type RazorDocsMetadataDiagnostic Describes one non-fatal RazorDocs metadata authoring problem discovered while parsing or normalizing metadata. Parameters Code Stable diagnostic code suitable for tests, logs, and documentation. FieldPath Metadata field path associated with the warning, such as featured_page_groups[0].pages . Problem Reader-facing summary of what is wrong. Cause Explanation of why RazorDocs cannot safely use the authored value as-is. Fix Suggested author action that resolves the warning. Type MarkdownMetadataParseResult Carries normalized metadata together with non-fatal diagnostics from a Markdown metadata parse. Parameters Metadata The parsed metadata, or null when no usable metadata document was present. Diagnostics Warnings produced while parsing or normalizing metadata fields. Type DocFeaturedPageResolver Resolves authored reader-intent landing curation metadata into browser-facing RazorDocs featured-page groups. Remarks The resolver accepts the normalized featured_page_groups metadata on a landing document, matches each authored destination against harvested docs by source or canonical path, skips destinations that are missing, hidden, blank, or duplicated, and returns only groups that still contain at least one visible page. Logging is intentionally warning-level because curation mistakes degrade first-run docs navigation without breaking application startup. Method ResolveGroups IReadOnlyList\u003CDocLandingFeaturedPageGroupViewModel\u003E ResolveGroups ( DocNode? landingDoc , IReadOnlyList\u003CDocNode\u003E docs ) Resolves grouped featured-page metadata from landingDoc against the harvested docs corpus. Parameters landingDoc The root or section landing document that owns the curation metadata, or null when the caller has no landing page to resolve. docs The harvested docs corpus used for destination lookup. Returns A list of resolved featured-page groups ordered by authored group order, then authored position. The method returns an empty list when landingDoc is null , when the landing doc has no featured_page_groups , or when every authored group is filtered out during resolution. Groups with no visible destinations after validation are omitted. Destinations that resolve to docs without a public DocNode.CanonicalPath are skipped with a warning because collision losers and reserved routes are intentionally not linkable. Duplicate destinations are suppressed across all groups, so a page resolved earlier in authored order will not appear again later in the landing. Browser-facing DocLandingFeaturedPageViewModel.Href values are rooted at the current live docs surface from DocsUrlBuilder , not hardcoded to /docs , and authored canonical input paths are matched against that same configured live docs root before the configured route-family root and legacy stable /docs prefix fallback are considered. Type RazorDocsHtmlSanitizer Sanitizes harvested RazorDocs HTML with the package-owned allowlist for docs content and highlighted code blocks. Remarks RazorDocs starts from the HtmlSanitizer defaults, adds the package-owned content tags section , article , header , details , summary , pre , code , and span , and allows the class , id , and open attributes. The sanitizer explicitly removes style from the default attribute set so harvested Markdown, generated API HTML, and server-side highlighted code can keep structural hooks while inline presentation and unsafe markup are stripped. Callers should pass already-rendered RazorDocs HTML through this sanitizer before display or export; supported semantic wrappers and token spans are preserved, while scripts, event handlers, inline styles, and unsupported attributes are discarded. Method Sanitize string Sanitize ( string html ) Sanitizes rendered documentation HTML using the RazorDocs allowlist. Parameters html The rendered HTML to sanitize. Returns Safe HTML that preserves RazorDocs structural markup and removes unsupported tags or attributes. Type RazorDocsCodeLanguage Describes RazorDocs\u0027 normalized view of an authored code-fence language token. Parameters NormalizedLanguage The stable RazorDocs language name. ClassLanguage The safe suffix used by the conventional language-* class. Label The reader-facing language label. TextMateLanguageId The TextMateSharp language id, or null for plaintext fallback. IsKnown Whether the authored token is part of RazorDocs\u0027 recognized language catalog. IsPlainText Whether the language should render as escaped plaintext. Type DocsUrlBuilder Builds canonical RazorDocs URLs for one RazorDocs route family. Remarks This builder centralizes the route contract so controllers, view components, views, and client scripts do not each guess how the docs surface is rooted. RouteRootPath is the stable route-family root used for archive and exact-version routes. CurrentDocsRootPath is the live source-backed docs root used for current docs, search, and current search-index routes. Most consumers should copy Routes rather than assembling route strings or calling lower-level builder methods directly. Method BuildHomeUrl string BuildHomeUrl () Builds the current live docs home URL. Returns The current docs home path. Method BuildSearchUrl string BuildSearchUrl () Builds the current live docs search workspace URL. Returns The app-relative search workspace URL for the current docs surface. Method BuildSearchIndexUrl string BuildSearchIndexUrl () Builds the current live docs search-index URL. Returns The app-relative search-index URL for the current docs surface. Method BuildSearchIndexRefreshUrl string BuildSearchIndexRefreshUrl () Builds the current live docs search-index refresh URL. Returns The app-relative authenticated refresh URL for the current docs search index. Method BuildHealthUrl string BuildHealthUrl () Builds the current live docs harvest health HTML URL. Returns The app-relative health page URL for the current docs surface. Method BuildHealthJsonUrl string BuildHealthJsonUrl () Builds the current live docs harvest health JSON URL. Returns The app-relative machine-readable health URL for the current docs surface. Method BuildSectionUrl string BuildSectionUrl ( DocPublicSection section ) Builds a current-surface public section URL. Parameters section The section whose route should be built. Returns The canonical section URL rooted at the current docs surface. Method BuildDocUrl 2 overloads string BuildDocUrl ( string path ) Builds a current-surface canonical document URL. Parameters path The source or canonical documentation path. Returns The canonical document URL rooted at the current docs surface. string BuildDocUrl ( string docsRootPath , string path ) Builds a canonical document URL rooted at an explicit docs surface root. Parameters docsRootPath The app-relative docs root path. path The source or canonical documentation path. Returns The canonical document URL. Method BuildAssetUrl string BuildAssetUrl ( string assetName ) Builds the current-surface search asset URL. Parameters assetName The asset file name, such as search.css . Returns The canonical asset URL rooted at the current docs surface. Method BuildVersionRootUrl string BuildVersionRootUrl ( string version ) Builds the exact-version root URL for one published docs release. Parameters version The exact published version identifier. Returns The canonical root URL for that version. Method BuildVersionDocUrl string BuildVersionDocUrl ( string version , string path ) Builds a canonical document URL rooted at a specific exact version. Parameters version The exact published version identifier. path The source or canonical documentation path. Returns The canonical document URL rooted at the requested version. Method BuildVersionsUrl string BuildVersionsUrl () Builds the public archive URL. Returns The stable archive URL. Method IsCurrentDocsPath bool IsCurrentDocsPath ( string? path ) Determines whether the supplied request path is inside the current live docs surface. Parameters path The request path to check. Returns true when the path belongs to the current live docs surface; otherwise false . Method IsUnderRoot bool IsUnderRoot ( string? path , string docsRootPath ) Determines whether a request path belongs to the supplied docs root. Parameters path The incoming request path to evaluate. docsRootPath The normalized docs root path configured for the live docs surface. Returns true when path resolves to the docs root itself or one of its child routes; otherwise false . Remarks Blank paths always return false . Root-mounted docs ( / ) use IsLikelyRootMountedDocsPath(string) so only known docs-like routes are treated as current docs traffic. Non-root mounts use case-insensitive exact and prefix matching against {docsRootPath}/... . Method JoinPath string JoinPath ( string docsRootPath , string relativePath ) Joins a normalized docs root with a relative docs route segment. Parameters docsRootPath The normalized app-relative docs root path. relativePath The relative docs route to append. Returns The combined app-relative route path. Remarks Leading slashes on relativePath are ignored. null , empty, and whitespace-only relative paths return the docs root unchanged. When the docs root is / , the result stays root-mounted instead of producing a doubled slash. Callers are expected to pass already-normalized root paths and docs-relative segments rather than arbitrary URLs. Method NormalizeDocsRootPath string NormalizeDocsRootPath ( string? docsRootPath , bool versioningEnabled ) Normalizes a configured docs root into the app-relative route contract RazorDocs uses at runtime. Parameters docsRootPath The configured docs root, which may be null, relative-looking, or already normalized. versioningEnabled Whether versioning is enabled and the default should therefore become /docs/next . Returns The normalized app-relative docs root path. Method NormalizeRouteRootPath string NormalizeRouteRootPath ( string? routeRootPath , string docsRootPath , bool versioningEnabled ) Normalizes a configured route-family root into the app-relative route contract RazorDocs uses at runtime. Parameters routeRootPath The configured route root, which may be null, relative-looking, or already normalized. docsRootPath The normalized live docs root used when versioning is disabled and no route root is configured. versioningEnabled Whether versioning is enabled and the default route family should remain /docs . Returns The normalized app-relative route-family root path. Property VersioningEnabled bool VersioningEnabled { get; } Gets a value indicating whether versioning is enabled for the current host. Property CurrentDocsRootPath string CurrentDocsRootPath { get; } Gets the canonical root path for the current live source-backed docs surface. Property RouteRootPath string RouteRootPath { get; } Gets the stable route-family root for this RazorDocs instance. Remarks The route root is the parent for the stable entry alias, version archive, and exact-version release trees. It is the same as CurrentDocsRootPath when versioning is disabled, and commonly the parent of the live preview root when versioning is enabled. For example, RouteRootPath=/foo/bar with DocsRootPath=/foo/bar/next keeps the archive at /foo/bar/versions while the live preview stays at /foo/bar/next . Property DocsEntryRootPath string DocsEntryRootPath { get; } Gets the docs entry path used as the stable public landing alias. Property DocsVersionPrefixPath string DocsVersionPrefixPath { get; } Gets the stable exact-version prefix for this route family. Property DocsVersionsRootPath string DocsVersionsRootPath { get; } Gets the stable archive path for this route family. Property Routes RazorDocsRouteReferences Routes { get; } Gets named RazorDocs routes that consumers should prefer over hardcoded route strings. Type RazorDocsRouteReferences Named RazorDocs routes for one configured route family. Remarks Consumers should prefer this record when they need well-known RazorDocs destinations in host code, operator guidance, generated configuration, or documentation. The values are app-relative. Views and other presentation boundaries apply request PathBase separately before sending browser-facing URLs. Method Deconstruct 2 overloads void Deconstruct ( out string home , out string search , out string searchIndex , out string searchIndexRefresh , out string versions ) Deconstructs the original route set for callers that used the positional record contract. Parameters home The current live docs home route. search The current live docs search workspace route. searchIndex The current live docs search-index JSON route. searchIndexRefresh The authenticated search-index refresh route. versions The route-family archive route. void Deconstruct ( out string home , out string search , out string searchIndex , out string searchIndexRefresh , out string versions , out string health , out string healthJson ) Deconstructs all known routes. Parameters home The current live docs home route. search The current live docs search workspace route. searchIndex The current live docs search-index JSON route. searchIndexRefresh The authenticated search-index refresh route. versions The route-family archive route. health The current live docs harvest health HTML route. healthJson The current live docs harvest health JSON route. Property Home string Home { get; init; } Gets the current live docs home route. Property Search string Search { get; init; } Gets the current live docs search workspace route. Property SearchIndex string SearchIndex { get; init; } Gets the current live docs search-index JSON route. Property SearchIndexRefresh string SearchIndexRefresh { get; init; } Gets the authenticated search-index refresh route. Property Versions string Versions { get; init; } Gets the route-family archive route, whether or not versioning endpoints are currently enabled. Property Health string Health { get; init; } Gets the current live docs harvest health HTML route. Property HealthJson string HealthJson { get; init; } Gets the current live docs harvest health JSON route. Type MarkdownHarvester Harvester implementation that scans Markdown source files and converts them into documentation nodes. Method HarvestAsync Task\u003CIReadOnlyList\u003CDocNode\u003E\u003E HarvestAsync ( string rootPath , CancellationToken cancellationToken = default ) Harvests Markdown files under the specified root directory and converts each into a DocNode containing a display title, relative path, generated HTML, metadata, and page outline. Parameters rootPath The root directory to search recursively for \u0060.md\u0060 files and an optional root \u0060LICENSE\u0060 file. cancellationToken An optional token to observe for cancellation requests. Returns A collection of DocNode objects representing each processed Markdown source file, including the display title, path relative to rootPath , generated HTML, metadata, and DocNode.Outline entries when outline headings are available. Remarks Skips files in excluded directories (for example \u0022node_modules\u0022, \u0022bin\u0022, \u0022obj\u0022, and \u0022Tests\u0022) and hidden dot-prefixed directories unless explicitly allowlisted. Dot-prefixed files are included. The root LICENSE file is also included when present so repository-relative license links can resolve in static exports. If a file\u0027s name is \u0022README\u0022 (case-insensitive), its title is set to the parent directory name or \u0022Home\u0022 for a repository root README. The Markdown body is parsed once with Markdown.Parse(markdownBody, _pipeline) ; HTML is rendered from that AST and DocNode.Outline is populated from the same AST with ExtractOutline so callers can rely on outline data being present when eligible headings are available. Files that fail to process are skipped and an error is logged. Method ReadMetadataSidecarAsync Task\u003CDocMetadata?\u003E ReadMetadataSidecarAsync ( string markdownFilePath , string relativeMarkdownPath , CancellationToken cancellationToken ) Reads an optional paired sidecar metadata file for a Markdown source document. Parameters markdownFilePath The absolute Markdown file path. relativeMarkdownPath The Markdown file path relative to the harvest root. cancellationToken A token that can cancel sidecar discovery or file reads. Returns The parsed sidecar metadata, or null when no valid sidecar applies. Remarks RazorDocs supports paired metadata files named {file}.yml and {file}.yaml such as README.md.yml . When both extensions exist for the same Markdown file, RazorDocs logs a warning and ignores both sidecars until the ambiguity is removed. Inline front matter remains the primary metadata source and overrides any overlapping sidecar fields. Method ExtractOutline IReadOnlyList\u003CDocOutlineItem\u003E ExtractOutline ( MarkdownDocument document ) Extracts page-local outline entries from Markdown heading blocks. Parameters document The parsed Markdown document whose heading blocks should be inspected. Returns A source-ordered list of DocOutlineItem values. Each item contains the rendered fragment DocOutlineItem.Id , normalized reader-facing DocOutlineItem.Title , and original heading DocOutlineItem.Level . Remarks Only HeadingBlock descendants with levels between MinOutlineHeadingLevel and MaxOutlineHeadingLevel are included, which means the built-in Markdown harvester emits H2-H3 headings by default. Fragment IDs come from HtmlAttributesExtensions.GetAttributes(heading).Id and titles are produced by NormalizeHeadingText(ExtractInlineText(heading.Inline)) . Headings without a non-empty fragment ID or normalized title are silently omitted; consumers and tests should account for those drops and for whitespace normalization when comparing outline titles. Method ExtractLeadingTitle string? ExtractLeadingTitle ( MarkdownDocument document ) Extracts the document title from a leading Markdown H1 when one exists. Parameters document The parsed Markdown document whose first block may be a page-title H1. Returns The normalized heading text from the leading H1, or null when the document starts with another block or the H1 has no readable text. Remarks This mirrors details-page H1 suppression: only the leading H1 can become package-owned page chrome. Later H1 elements remain body structure and do not replace filename or metadata title fallback behavior. Method ExtractInlineText string ExtractInlineText ( ContainerInline? inline ) Extracts plain reader-facing text from a Markdig inline container for outline display. Parameters inline The inline container to flatten. Returns The extracted text, or an empty string when no inline content exists. Method NormalizeHeadingText string NormalizeHeadingText ( string value ) Normalizes heading text by collapsing whitespace without introducing leading spaces. Parameters value The raw heading text. Returns The normalized heading text. Type DocLinkTargetManifest Enumerates the documentation targets harvested into a RazorDocs snapshot so link rewriting can avoid guessing from file extensions alone. Remarks The manifest stores both source paths, such as guides/start.md , and canonical browser paths, such as guides/start.md.html . Query strings and fragments are intentionally ignored because anchors and query parameters decorate a page target rather than defining a separate harvested document. Method FromNodes DocLinkTargetManifest FromNodes ( IEnumerable\u003CDocNode\u003E nodes ) Creates a manifest from harvested documentation nodes. Parameters nodes The harvested documentation nodes that may be linked through RazorDocs routes. Returns A manifest containing source and canonical target forms for the supplied nodes. Method FromPaths DocLinkTargetManifest FromPaths ( IEnumerable\u003Cstring?\u003E paths ) Creates a manifest from source or canonical documentation paths. Parameters paths The documentation paths to register as known link targets. Returns A manifest containing normalized source and canonical target forms. Method Contains bool Contains ( string? path ) Determines whether the supplied path resolves to a harvested documentation target. Parameters path A source or canonical documentation path, optionally rooted, queried, or fragmented. Returns true when the normalized target is in the manifest; otherwise false . Type DocRoutePath Normalizes harvested non-Markdown source paths into legacy browser-facing routes used by RazorDocs. Remarks A harvested source path is the repository-relative or generated path assigned to a DocNode before RazorDocs publishes it. This helper is intentionally narrow: it exists for generated or imported non-Markdown sources such as XML API reference pages, generated JSON or YAML API specs, and imported HTML fragments that still use the historical .html route shape. Markdown documents should use DocRouteIdentityCatalog instead, because that catalog owns clean public routes, redirect aliases, collisions, and reserved-route diagnostics. Method BuildCanonicalPath string BuildCanonicalPath ( string sourcePath ) Constructs a legacy browser-facing path for a harvested non-Markdown documentation source path. Parameters sourcePath The harvested source path, optionally including a fragment. Returns The legacy docs route path, including the .html suffix used by generated API docs and any original fragment identifier. Markdown public routes are owned by DocRouteIdentityCatalog . Remarks Use this method only when a source must keep the generated-docs compatibility contract where Namespaces/Foo.Bar becomes Namespaces/Foo.Bar.html . It trims leading and trailing separators, preserves fragments, normalizes backslashes to slashes, and appends .html unless the final file name already has that suffix. The word \u0022canonical\u0022 in the method name refers to this legacy generated-doc route canonicalization; it does not mean the clean Markdown route contract. For authored Markdown pages, callers should query DocRouteIdentityCatalog so explicit canonical_slug , redirect aliases, public-route collisions, and reserved-route checks all remain centralized. Type IRazorDocsHtmlSanitizer Sanitizes rendered RazorDocs HTML using the package\u0027s docs-specific allowlist. Remarks IRazorDocsHtmlSanitizer exists to normalize rendered package documentation fragments before RazorDocs displays them. It is not a general-purpose user-generated-content sanitizer, JavaScript policy, or replacement for a host-owned Content Security Policy. Unsupported elements or attributes may be removed. Method Sanitize string Sanitize ( string html ) Sanitizes the provided HTML fragment. Parameters html The rendered RazorDocs HTML fragment to sanitize. Returns The sanitized HTML fragment. Remarks Sanitize expects a non-null rendered RazorDocs HTML fragment, not a complete document or unrendered template. Implementations should throw ArgumentNullException when html is null and should preserve already-encoded text rather than double-encoding it. Type RazorDocsCodeLanguageCatalog Owns Markdown code-fence language normalization, safe CSS class suffixes, and TextMateSharp lookup ids. Method Normalize RazorDocsCodeLanguage Normalize ( string? language ) Normalizes an authored language token into RazorDocs\u0027 stable language contract. Parameters language The raw first info-string token. Returns A safe language descriptor for rendering and TextMate lookup. Method CreateSafeClassSlug string CreateSafeClassSlug ( string value ) Converts arbitrary language input into a CSS-safe lowercase ASCII slug. Parameters value The value to slug. Returns A lowercase slug containing only ASCII letters, digits, and hyphens. Type TextMateSharpRazorDocsCodeHighlighter TextMateSharp-backed implementation of RazorDocs\u0027 internal code-block highlighting contract. Method LoadGrammar IGrammar? LoadGrammar ( RazorDocsCodeLanguage language ) Loads the TextMate grammar for a normalized language, returning null when no grammar exists. Parameters language The normalized language descriptor. Returns The loaded grammar, or null when the language has no TextMate scope. Method AppendTokens void AppendTokens ( StringBuilder builder , string line , IReadOnlyList\u003CIToken\u003E tokens ) Appends a tokenized source line while preserving unclassified gaps and trailing text. Parameters builder The destination HTML builder. line The original source line. tokens TextMate tokens for the line. Method ResolveTokenClass string? ResolveTokenClass ( IReadOnlyList\u003Cstring\u003E scopes ) Maps TextMate scopes to RazorDocs\u0027 small semantic token vocabulary. Parameters scopes The scopes attached to a TextMate token. Returns The RazorDocs token modifier, or null for unstyled scopes. Type DocsSearchIndexPayload Cached search-index payload for the live source-backed docs surface. Parameters Metadata Static metadata emitted alongside the indexed documents. Documents Searchable docs entries in the shape consumed by the built-in MiniSearch client. Type DocsSearchIndexMetadata Metadata emitted with each docs search-index payload. Parameters GeneratedAtUtc UTC timestamp for when the snapshot was generated. Version Schema version understood by the search client. Engine Client-side search engine identifier. Type DocsSearchIndexDocument Search document entry emitted for the built-in docs search experience. Parameters Id Stable identifier for the indexed document. Path Browser-facing docs URL used for result navigation. Title Display title shown in search results. Summary Summary text favored for recovery and preview UI. Headings Normalized heading titles harvested from the document outline. BodyText Full normalized body text indexed for recall. Snippet Short excerpt shown in search results. PageType Page-type facet value. PageTypeLabel Resolved page-type badge label. PageTypeVariant Resolved page-type badge variant. Audience Audience facet value when explicitly authored. Component Component facet value when explicitly authored. Aliases Alternative phrases that should match the page. Keywords Additional authored search keywords. Status Status facet value. NavGroup Public navigation group label when present. PublicSection Resolved public-section slug when the page participates in a public section. PublicSectionLabel Human-readable public-section label. IsSectionLanding Whether this record is the resolved landing page for its public section. Order Authored order hint used for browse sorting. SequenceKey Optional authored sequence key for related content. CanonicalSlug Optional canonical slug used for route continuity. RelatedPages Authored related-page references used for recovery links. Breadcrumbs Authored breadcrumb labels displayed in result chrome. SourcePath Repository-relative source path retained for provenance and custom integrations. Remarks The Path value is cached relative to the live docs surface root and can be rebased onto a request PathBase at response time without rebuilding the full snapshot. Lists are serialized as JSON arrays so the browser client can preserve exact ordering for headings, aliases, related pages, and breadcrumbs. Type DocAggregator Service responsible for aggregating documentation from multiple harvesters and caching the results. Method GetDocsAsync Task\u003CIReadOnlyList\u003CDocNode\u003E\u003E GetDocsAsync ( CancellationToken cancellationToken = default ) Retrieves all harvested documentation nodes sorted by their Path. Parameters cancellationToken An optional token to observe for cancellation requests. Returns A read-only list of all DocNode objects ordered by their Path. Method GetHarvestHealthAsync Task\u003CDocHarvestHealthSnapshot\u003E GetHarvestHealthAsync ( CancellationToken cancellationToken = default ) Returns structured health for the current RazorDocs harvest snapshot. Parameters cancellationToken An optional token to observe while waiting for the cached snapshot. Returns Structured harvest health that distinguishes valid empty docs from failed or degraded harvests. Remarks The health snapshot is produced by the same memoized harvest used by GetDocsAsync(CancellationToken) . If no docs snapshot exists yet, calling this method triggers the same snapshot generation as a docs read. Caller cancellation cancels only the caller\u0027s wait; it does not cancel or poison the shared snapshot computation. Method GetDocByPathAsync Task\u003CDocNode?\u003E GetDocByPathAsync ( string path , CancellationToken cancellationToken = default ) Retrieves a documentation node for a source path or canonical docs path. Parameters path The source or canonical documentation path to look up. cancellationToken An optional token to observe while waiting for the cached snapshot. Returns The matching DocNode , or null if no node exists for the given path. Remarks The lookup awaits the cached docs snapshot, then delegates to the snapshot\u0027s DocPathResolver so legacy source paths, generated canonical .html paths, fragments, separators, and casing follow the same matching rules used by details pages and curated links. Method ResolvePublicRouteAsync Task\u003CDocRouteResolution\u003E ResolvePublicRouteAsync ( string path , CancellationToken cancellationToken = default ) Resolves a requested browser-facing docs route against the current snapshot route catalog. Parameters path The non-null request path to resolve. Callers may pass a docs-relative route such as packages , a rooted docs path such as /docs/packages , or a source-shaped path. Markdown source-shaped paths for public winners resolve as redirects to their clean public routes; non-Markdown source paths, collision losers, and reserved routes remain non-public. cancellationToken An optional token observed while waiting for the cached docs snapshot. Returns A DocRouteResolution whose kind tells callers whether the request is the canonical public route, a declared or Markdown source-shaped alias that should redirect to DocRouteResolution.PublicRoutePath , an internal non-Markdown source match, a collision or reserved-route loser, or an unresolved path. Remarks This method does not redirect or mutate the snapshot. It awaits GetCachedDocsSnapshotAsync , then delegates to DocRouteIdentityCatalog.ResolvePublicRoute(string) so controllers and link builders branch on the same route identity semantics. Markdown source-shaped redirects let links copied from GitHub or editor paths recover to their published canonical routes instead of falling into the generic 404 page. Method GetDocDetailsAsync Task\u003CDocDetailsViewModel?\u003E GetDocDetailsAsync ( string path , CancellationToken cancellationToken = default ) Builds the typed details view model for the specified documentation page. Parameters path The documentation path to resolve. cancellationToken An optional token to observe for cancellation requests. Returns A DocDetailsViewModel containing the resolved page, its in-page outline, and wayfinding links, or null when the page cannot be resolved. Method GetSearchIndexPayloadAsync Task\u003CDocsSearchIndexPayload\u003E GetSearchIndexPayloadAsync ( CancellationToken cancellationToken = default ) Returns the docs search-index payload generated during docs aggregation. Parameters cancellationToken An optional token to observe for cancellation requests. Returns A typed payload containing the search metadata and documents emitted by the live docs surface. The payload is cached before response serialization so callers can rebase rooted paths, such as /docs/guide.html , onto a request PathBase without reparsing or reserializing an intermediate JSON node graph. Method GetPublicSectionsAsync Task\u003CIReadOnlyList\u003CDocSectionSnapshot\u003E\u003E GetPublicSectionsAsync ( CancellationToken cancellationToken = default ) Returns the normalized public-section snapshots derived from the harvested docs corpus. Parameters cancellationToken An optional token to observe for cancellation requests. Returns The ordered public sections visible in the current docs snapshot. Method GetPublicSectionAsync Task\u003CDocSectionSnapshot?\u003E GetPublicSectionAsync ( DocPublicSection section , CancellationToken cancellationToken = default ) Returns one normalized public-section snapshot when the section is present in the current docs snapshot. Parameters section The public section to resolve. cancellationToken An optional token to observe for cancellation requests. Returns The matching section snapshot, or null when the section has no visible public pages. Method InvalidateCache void InvalidateCache () Invalidates the cached docs snapshot so docs and search-index are rebuilt on next access. Method GetCachedDocsSnapshotAsync Task\u003CCachedDocsSnapshot\u003E GetCachedDocsSnapshotAsync () Retrieves the cached docs snapshot, harvesting docs and generating the search-index payload when absent. Returns A cached snapshot containing both docs and search-index payload. Remarks When harvesting, each configured harvester is invoked; failures from individual harvesters are caught and logged. Contents are sanitized before being cached. If multiple nodes share the same Path, a warning is logged and the first occurrence is retained. The search-index payload is generated from the same harvested snapshot. Caller cancellation does not cancel shared snapshot computation; callers can cancel their own wait. Harvester execution is bounded by a timeout so a single slow harvester cannot block snapshot regeneration indefinitely. The memoized cache entry is created with the configured absolute expiration from RazorDocsOptions.CacheExpirationMinutes . Method ResolveGitLastUpdatedUtcAsync Task\u003CDateTimeOffset?\u003E ResolveGitLastUpdatedUtcAsync ( string repositoryRoot , string sourcePath , ILogger logger , CancellationToken cancellationToken , Func\u003Cstring, IReadOnlyList\u003Cstring\u003E, string, ILogger, CancellationToken, Task\u003CCommandResult\u003E\u003E? executeProcessAsync = null ) Resolves the last committed UTC timestamp for a source path from local git history. Parameters repositoryRoot The repository root used as the git working directory. sourcePath The repository-relative source path to inspect. logger Logger used for diagnostic output when git is unavailable or returns unusable data. cancellationToken Cancellation used to abort the lookup when snapshot generation times out. executeProcessAsync Optional process-execution seam used by tests to simulate git output and failure modes without mutating machine-level PATH state. Returns The exact last-updated UTC timestamp when git returns a parseable ISO 8601 commit date; otherwise null . Method BuildPublicSections IReadOnlyList\u003CDocSectionSnapshot\u003E BuildPublicSections ( IEnumerable\u003CDocNode\u003E docs , ILogger logger ) Builds the public-section snapshots from the harvested docs corpus. Parameters docs The harvested docs to classify. logger Logger used for section-landing conflict warnings. Returns The ordered public sections that have at least one visible page. Method BuildSearchIndexPayload (DocsSearchIndexPayload Payload, int RecordCount) BuildSearchIndexPayload ( IEnumerable\u003CDocNode\u003E docs , IReadOnlyList\u003CDocSectionSnapshot\u003E publicSections , DocRouteIdentityCatalog routeIdentityCatalog ) Builds the search-index payload from the harvested documentation nodes. Parameters docs The documentation nodes to index. publicSections The resolved public sections used to derive landing winners. routeIdentityCatalog The snapshot route catalog used to emit public canonical paths. Returns A tuple containing the serializable payload and the number of records indexed. Method NormalizeSearchText string NormalizeSearchText ( string? text ) Decodes HTML entities and normalizes whitespace in the provided text for search indexing. Parameters text The text to normalize. Returns The normalized text. Method BuildSearchDocUrl 2 overloads string BuildSearchDocUrl ( string path ) Constructs a browser-facing URL for a documentation path. Parameters path The relative documentation path. Returns A URL string starting with \u0022/docs\u0022. string BuildSearchDocUrl ( string docsRootPath , string path ) Constructs a browser-facing URL for a documentation path rooted at a specific docs surface. Parameters docsRootPath The app-relative docs root path. path The relative documentation path. Returns A URL string rooted at docsRootPath . Method TruncateSnippetAtWordBoundary string TruncateSnippetAtWordBoundary ( string text , int maxLength ) Truncates a text snippet at the last word boundary before the maximum length is exceeded. Parameters text The text to truncate. maxLength The maximum allowed length of the snippet. Returns The truncated text with an ellipsis if it was shortened. Method MergeNamespaceReadmes void MergeNamespaceReadmes ( List\u003CDocNode\u003E nodes ) Merges README content into the corresponding namespace overview pages. Parameters nodes The list of documentation nodes to process; README nodes used for merging are removed from this list. Method MergeNamespaceIntroIntoContent string MergeNamespaceIntroIntoContent ( string namespaceContent , string readmeContent ) Inserts README content into a namespace overview page after the auto-generated namespace groups. Parameters namespaceContent The auto-generated HTML content for the namespace page. readmeContent The HTML content from the README file. A leading rendered Markdown H1 is removed before the README is wrapped because namespace overview pages render their primary H1 in the surrounding details shell. Returns The merged HTML content, with any leading README H1 omitted from the namespace intro section. Method FindMatchingSectionEnd int FindMatchingSectionEnd ( string content , int sectionStart ) Finds the index of the closing \u003C/section\u003E tag that matches a \u003Csection\u003E tag starting at the specified index. Parameters content The HTML content to search. sectionStart The starting index of the \u003Csection\u003E tag. Returns The index of the closing tag, or -1 if no match is found. Method IsReadmePath bool IsReadmePath ( string path ) Determines whether the specified path points to a documentation README file. Parameters path The path to check. Returns true if the path identifies a README.md file; otherwise, false . Method ExtractNamespaceNameFromNamespacePath string ExtractNamespaceNameFromNamespacePath ( string path ) Extracts the dotted namespace name from a documentation path under the \u0022Namespaces/\u0022 directory. Parameters path The path to process. Returns The extracted namespace name. Method ExtractNamespaceNameFromReadmePath 2 overloads string? ExtractNamespaceNameFromReadmePath ( string path ) Attempts to extract a namespace name from a README path by looking at the parent directory name. Parameters path The README path to process. Returns The extracted namespace name, or null if it cannot be determined. string? ExtractNamespaceNameFromReadmePath ( string path , IEnumerable\u003Cstring\u003E? knownNamespaceNames ) Extracts a namespace name from a README path, optionally matching against a list of known namespaces. Parameters path The README path to process. knownNamespaceNames Optional list of known namespaces to match directory segments against. When provided, README paths are only treated as namespace introductions when the matching namespace folder appears under a trusted container directory such as docs or Namespaces . Returns The extracted namespace name, or null if it cannot be determined. Method HasNamespaceReadmePrefix bool HasNamespaceReadmePrefix ( IReadOnlyList\u003Cstring\u003E parts , int namespaceStartIndex ) Determines whether the matched namespace folder appears in one of the supported namespace README locations. Parameters parts The normalized directory path segments that precede README.md . namespaceStartIndex The index where the matched namespace name begins within parts . Returns true when the namespace folder lives under a trusted container like docs or Namespaces ; otherwise, false . Method NormalizeLookupPath string NormalizeLookupPath ( string path ) Normalizes a documentation path for lookup by trimming slashes and removing fragment anchors. Parameters path The path to normalize. Returns The normalized lookup path. Method GetFragment string? GetFragment ( string path ) Extracts the fragment anchor (after the \u0027#\u0027) from a documentation path. Parameters path The path to process. Returns The fragment string, or null if no fragment is present. Property SnapshotCacheDuration TimeSpan SnapshotCacheDuration { get; } Gets the configured absolute lifetime for the shared docs snapshot cache. Type RazorDocsHighlightedCode Contains RazorDocs-owned HTML for a rendered Markdown code block. Parameters Html The complete sanitized-shape HTML fragment for the code block. NormalizedLanguage The normalized language identifier used by RazorDocs. IsHighlighted Whether token spans were emitted for the code body. Type DocContentLinkRewriter Rewrites harvested documentation links so authored Markdown can use repository-relative source links while the rendered docs experience still navigates through canonical RazorDocs routes. Method RewriteInternalDocLinks string RewriteInternalDocLinks ( string sourcePath , string html , string docsRootPath , DocLinkTargetManifest targetManifest ) Rewrites internal documentation anchors in rendered HTML so they point at canonical RazorDocs routes and carry Turbo navigation attributes that keep browser history aligned with frame navigation. Parameters sourcePath The harvested source path whose content is being rewritten. html The rendered and sanitized HTML fragment to rewrite. docsRootPath The app-relative docs root path that should own rewritten links. targetManifest Manifest of harvested documentation targets that may be rewritten to docs routes. Returns The rewritten HTML fragment. Method PrefixPathBaseForDocsUrls string PrefixPathBaseForDocsUrls ( string html , string docsRootPath , string? requestPathBase , string routeRootPath = DocsUrlBuilder.DocsEntryPath ) Prefixes request PathBase for rooted docs-local anchor hrefs in rendered HTML content. Parameters html The rendered HTML fragment whose rooted docs-local links should honor the current request path base. docsRootPath The current live docs root that owns source-backed documentation routes. requestPathBase The request path base that should prefix rooted docs-local hrefs when present. routeRootPath The route-family root that owns stable entry, archive, and exact-version routes. Returns The original fragment when no path base applies or no docs-local rooted links are present; otherwise a fragment whose docs-local anchor hrefs are prefixed so mounted apps stay inside their virtual root. Remarks This helper intentionally scopes itself to docs-local routes rather than all rooted links. Authored content may legitimately include other site-rooted links that should remain outside the docs shell, while docs-local links generated by RewriteInternalDocLinks(string,string,string,DocLinkTargetManifest) must stay within the current mounted app.","snippet":"Type CSharpDocHarvester Harvester implementation that scans C# source files for XML documentation comments. Method HarvestAsync Task\u003CIReadOnlyList\u003CDocNode\u003E\u003E HarvestAsync ( string rootPath , CancellationToken...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-CSharpDocHarvester","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-CSharpDocHarvester","title":"CSharpDocHarvester","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","CSharpDocHarvester"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-CSharpDocHarvester"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-CSharpDocHarvester-NamespaceDocPage","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-CSharpDocHarvester-NamespaceDocPage","title":"NamespaceDocPage","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","NamespaceDocPage"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-CSharpDocHarvester-NamespaceDocPage"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocAggregator","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocAggregator","title":"DocAggregator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocAggregator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocAggregator"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocContentLinkRewriter","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocContentLinkRewriter","title":"DocContentLinkRewriter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocContentLinkRewriter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocContentLinkRewriter"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocFeaturedPageResolver","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocFeaturedPageResolver","title":"DocFeaturedPageResolver","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocFeaturedPageResolver"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocFeaturedPageResolver"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocLinkTargetManifest","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocLinkTargetManifest","title":"DocLinkTargetManifest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocLinkTargetManifest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocLinkTargetManifest"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocMetadataFactory","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocMetadataFactory","title":"DocMetadataFactory","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocMetadataFactory"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocMetadataFactory"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocPathResolver","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocPathResolver","title":"DocPathResolver","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocPathResolver"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocPathResolver"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocRouteIdentityCatalog","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocRouteIdentityCatalog","title":"DocRouteIdentityCatalog","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocRouteIdentityCatalog"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocRouteIdentityCatalog"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocRoutePath","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocRoutePath","title":"DocRoutePath","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocRoutePath"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocRoutePath"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexDocument","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexDocument","title":"DocsSearchIndexDocument","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocsSearchIndexDocument"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexDocument"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexMetadata","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexMetadata","title":"DocsSearchIndexMetadata","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocsSearchIndexMetadata"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexMetadata"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexPayload","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexPayload","title":"DocsSearchIndexPayload","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocsSearchIndexPayload"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocsSearchIndexPayload"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsUrlBuilder","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-DocsUrlBuilder","title":"DocsUrlBuilder","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","DocsUrlBuilder"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-DocsUrlBuilder"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-HarvestPathExclusions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-HarvestPathExclusions","title":"HarvestPathExclusions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","HarvestPathExclusions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-HarvestPathExclusions"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-IRazorDocsCodeHighlighter","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-IRazorDocsCodeHighlighter","title":"IRazorDocsCodeHighlighter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","IRazorDocsCodeHighlighter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-IRazorDocsCodeHighlighter"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-IRazorDocsHtmlSanitizer","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-IRazorDocsHtmlSanitizer","title":"IRazorDocsHtmlSanitizer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","IRazorDocsHtmlSanitizer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-IRazorDocsHtmlSanitizer"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-MarkdownFrontMatterParser","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-MarkdownFrontMatterParser","title":"MarkdownFrontMatterParser","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","MarkdownFrontMatterParser"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-MarkdownFrontMatterParser"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-MarkdownHarvester","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-MarkdownHarvester","title":"MarkdownHarvester","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","MarkdownHarvester"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-MarkdownHarvester"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-MarkdownMetadataParseResult","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-MarkdownMetadataParseResult","title":"MarkdownMetadataParseResult","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","MarkdownMetadataParseResult"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-MarkdownMetadataParseResult"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlock","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlock","title":"RazorDocsCodeBlock","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsCodeBlock"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlock"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlockMarkdownExtension","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlockMarkdownExtension","title":"RazorDocsCodeBlockMarkdownExtension","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsCodeBlockMarkdownExtension"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlockMarkdownExtension"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlockRenderer","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlockRenderer","title":"RazorDocsCodeBlockRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsCodeBlockRenderer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeBlockRenderer"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeLanguage","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeLanguage","title":"RazorDocsCodeLanguage","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsCodeLanguage"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeLanguage"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeLanguageCatalog","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeLanguageCatalog","title":"RazorDocsCodeLanguageCatalog","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsCodeLanguageCatalog"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsCodeLanguageCatalog"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHarvestFailurePreflightService","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHarvestFailurePreflightService","title":"RazorDocsHarvestFailurePreflightService","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsHarvestFailurePreflightService"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsHarvestFailurePreflightService"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHarvestHealthVisibility","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHarvestHealthVisibility","title":"RazorDocsHarvestHealthVisibility","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsHarvestHealthVisibility"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsHarvestHealthVisibility"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHeadingSuppressor","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHeadingSuppressor","title":"RazorDocsHeadingSuppressor","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsHeadingSuppressor"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsHeadingSuppressor"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHighlightedCode","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHighlightedCode","title":"RazorDocsHighlightedCode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsHighlightedCode"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsHighlightedCode"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHtmlSanitizer","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsHtmlSanitizer","title":"RazorDocsHtmlSanitizer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsHtmlSanitizer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsHtmlSanitizer"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsMetadataDiagnostic","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsMetadataDiagnostic","title":"RazorDocsMetadataDiagnostic","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsMetadataDiagnostic"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsMetadataDiagnostic"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeContentRewriter","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeContentRewriter","title":"RazorDocsPublishedTreeContentRewriter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsPublishedTreeContentRewriter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeContentRewriter"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeHandler","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeHandler","title":"RazorDocsPublishedTreeHandler","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsPublishedTreeHandler"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeHandler"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeMount","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeMount","title":"RazorDocsPublishedTreeMount","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsPublishedTreeMount"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsPublishedTreeMount"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersion","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersion","title":"RazorDocsResolvedVersion","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsResolvedVersion"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersion"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersionCatalog","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersionCatalog","title":"RazorDocsResolvedVersionCatalog","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsResolvedVersionCatalog"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersionCatalog"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersionCatalogStatus","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersionCatalogStatus","title":"RazorDocsResolvedVersionCatalogStatus","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsResolvedVersionCatalogStatus"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsResolvedVersionCatalogStatus"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsRouteReferences","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsRouteReferences","title":"RazorDocsRouteReferences","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsRouteReferences"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsRouteReferences"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsVersionCatalogService","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-RazorDocsVersionCatalogService","title":"RazorDocsVersionCatalogService","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","RazorDocsVersionCatalogService"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-RazorDocsVersionCatalogService"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-TextMateSharpRazorDocsCodeHighlighter","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Services.html#ForgeTrust-AppSurface-Docs-Services-TextMateSharpRazorDocsCodeHighlighter","title":"TextMateSharpRazorDocsCodeHighlighter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Services","TextMateSharpRazorDocsCodeHighlighter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Services#ForgeTrust-AppSurface-Docs-Services-TextMateSharpRazorDocsCodeHighlighter"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Standalone.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Standalone.html","title":"Standalone","summary":"Type RazorDocsStandaloneHost Creates and runs the standalone RazorDocs host used by the executable wrapper and integration tests. Remarks Use this type when code needs the same host shape as Program.cs without...","headings":["RazorDocsStandaloneHost","RunAsync","CreateBuilder"],"bodyText":"Type RazorDocsStandaloneHost Creates and runs the standalone RazorDocs host used by the executable wrapper and integration tests. Remarks Use this type when code needs the same host shape as Program.cs without shelling out to dotnet run . The builder keeps the RazorDocs root module, routes, static web assets, and configuration binding on the normal AppSurface Web startup path. CreateBuilder is a low-level host-builder seam; callers that start the host themselves should pass an explicit endpoint or configure the web host before building. Method RunAsync 2 overloads Task RunAsync ( string[] args ) Runs the standalone RazorDocs web application until the host shuts down. Parameters args Command-line arguments forwarded to the AppSurface Web startup pipeline. Returns A task that completes when the host exits. Task RunAsync ( string[] args , Action\u003CWebOptions\u003E? configureOptions ) Runs the standalone RazorDocs web application with optional host web-option customization. Parameters args Command-line arguments forwarded to the AppSurface Web startup pipeline. configureOptions Optional web-options callback applied after module defaults, before the host is built. Package-hosted command-line tools use this seam to disable static-web-asset manifest loading when their required assets are embedded in assemblies instead. Returns A task that completes when the host exits. Method CreateBuilder 2 overloads IHostBuilder CreateBuilder ( string[] args , IEnvironmentProvider? environmentProvider = null ) Creates a configured host builder for the standalone RazorDocs application without starting it. Parameters args Command-line arguments forwarded to the Generic Host and RazorDocs configuration binder. environmentProvider Optional environment provider used by AppSurface startup decisions before the Generic Host has been built. Leave unset for normal executable startup; tests can pass a fixed provider to avoid process-wide environment variable mutation. Returns An IHostBuilder for the standalone RazorDocs application. Remarks The builder pins the standalone assembly as the entry point identity so in-process test hosts still resolve the same static web asset manifest that the executable resolves. Without that override, test runners would use their own process entry assembly and miss RazorDocs assets. This overload is kept for source and binary compatibility; use the three-parameter overload when a packaged tool needs to customize AppSurface Web options. IHostBuilder CreateBuilder ( string[] args , IEnvironmentProvider? environmentProvider , Action\u003CWebOptions\u003E? configureOptions = null ) Creates a configured host builder for the standalone RazorDocs application without starting it. Parameters args Command-line arguments forwarded to the Generic Host and RazorDocs configuration binder. environmentProvider Optional environment provider used by AppSurface startup decisions before the Generic Host has been built. Leave unset for normal executable startup; tests can pass a fixed provider to avoid process-wide environment variable mutation. configureOptions Optional web-options callback applied after module defaults, before the host is built. Returns An IHostBuilder for the standalone RazorDocs application. Remarks This overload preserves the original two-parameter CreateBuilder method for already-compiled callers while giving packaged tools a host-shape seam for static-web-asset and startup-watchdog options.","snippet":"Type RazorDocsStandaloneHost Creates and runs the standalone RazorDocs host used by the executable wrapper and integration tests. Remarks Use this type when code needs the same host shape as Program.cs without...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Standalone"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Standalone"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.Standalone.html#ForgeTrust-AppSurface-Docs-Standalone-RazorDocsStandaloneHost","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.Standalone.html#ForgeTrust-AppSurface-Docs-Standalone-RazorDocsStandaloneHost","title":"RazorDocsStandaloneHost","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","Standalone","RazorDocsStandaloneHost"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.Standalone#ForgeTrust-AppSurface-Docs-Standalone-RazorDocsStandaloneHost"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html","title":"ViewComponents","summary":"Type SidebarViewComponent A view component that renders the sidebar navigation for public documentation sections. Remarks The component returns a DocSidebarViewModel whose DocSidebarViewModel.Sections contain...","headings":["SidebarViewComponent","InvokeAsync","ResolveHarvestHealthAsync","SidebarDisplayHelper","GetGroupName","NormalizeGroupName","IsTypeAnchorNode","GetFullNamespaceName","GetNamespaceFamily","GetNamespaceDisplayName","SimplifyNamespace","GetDerivedNamespacePrefixes","GetLastNamespaceSegment","DocSectionDisplayBuilder","BuildGroups"],"bodyText":"Type SidebarViewComponent A view component that renders the sidebar navigation for public documentation sections. Remarks The component returns a DocSidebarViewModel whose DocSidebarViewModel.Sections contain normalized public section links and whose DocSidebarViewModel.HarvestHealth is populated only when harvest health chrome is visible for the configured options and host environment. Method InvokeAsync Task\u003CIViewComponentResult\u003E InvokeAsync () Retrieves the normalized public sections and optional harvest health chrome, then shapes them into the sidebar display model. Returns A view result containing the section-first sidebar view model and optional harvest health chrome. Remarks InvokeAsync returns a DocSidebarViewModel whose sections come from normalized public section snapshots and whose DocSidebarViewModel.HarvestHealth value is resolved by ResolveHarvestHealthAsync . Harvest health is controlled by RazorDocsHarvestHealthVisibility and may be null when chrome is hidden. When present, it contains a DocSidebarHarvestHealthViewModel.Status , DocSidebarHarvestHealthViewModel.Ok , and an optional DocSidebarHarvestHealthViewModel.Href . The href is omitted when chrome is visible but health routes are not exposed. Health resolution uses DocAggregator.GetHarvestHealthAsync(CancellationToken) , links with DocsUrlBuilder.BuildHealthUrl , and observes the current request\u0027s aborted token. Method ResolveHarvestHealthAsync Task\u003CDocSidebarHarvestHealthViewModel?\u003E ResolveHarvestHealthAsync () Resolves the optional harvest health chrome view model for the current sidebar request. Returns The sidebar harvest health view model, or null when chrome is hidden. Remarks Returns null when RazorDocsHarvestHealthVisibility.ShouldShowChrome(RazorDocsOptions, IHostEnvironment) hides chrome. Otherwise it reads the current harvest snapshot through DocAggregator.GetHarvestHealthAsync(CancellationToken) , maps the status and verification result, and supplies an href from DocsUrlBuilder.BuildHealthUrl only when RazorDocsHarvestHealthVisibility.AreRoutesExposed(RazorDocsOptions, IHostEnvironment) exposes the operator route. The aggregation wait respects HttpContext.RequestAborted when a view context is available. Type SidebarDisplayHelper Normalizes RazorDocs sidebar labels, grouping, and namespace display names. Remarks SidebarDisplayHelper treats the authored Namespaces route family specially so API reference pages stay grouped together. Path inputs are trimmed, slash-normalized, and allowed to be empty only where the method explicitly documents the fallback. Method GetGroupName 2 overloads string GetGroupName ( DocNode node ) Gets the sidebar group for a documentation node, honoring explicit metadata except for namespace pages. Parameters node The documentation node to classify. Returns The normalized group name, Namespaces for namespace pages, or a path-derived fallback. string GetGroupName ( string path ) Gets the sidebar group implied by a source path. Parameters path A source or docs path. Directory separators and leading or trailing slashes are normalized. Returns Namespaces for namespace paths, General for root files, or the containing directory. Method NormalizeGroupName string? NormalizeGroupName ( string? groupName ) Trims an authored group name and converts blank values to null . Parameters groupName The authored group name. Returns A trimmed group name, or null when no meaningful group was authored. Method IsTypeAnchorNode bool IsTypeAnchorNode ( DocNode node ) Determines whether a node represents a generated type-anchor entry below a parent API page. Parameters node The node to inspect. Returns true when the node has a parent, no body content, and a fragment path. Method GetFullNamespaceName string GetFullNamespaceName ( DocNode node ) Gets the full namespace represented by a namespace documentation node. Parameters node A node from the Namespaces route family or a fallback titled node. Returns The namespace path after Namespaces/ , an empty string for the root, or the node title fallback. Method GetNamespaceFamily string GetNamespaceFamily ( string fullNamespace , IReadOnlyList\u003Cstring\u003E namespacePrefixes ) Gets the top-level namespace family after configured prefix simplification. Parameters fullNamespace The full namespace to simplify. namespacePrefixes Prefixes that may be removed before family extraction. Returns The first simplified namespace segment, or the whole simplified value when it has no dot. Method GetNamespaceDisplayName string GetNamespaceDisplayName ( string fullNamespace , IReadOnlyList\u003Cstring\u003E namespacePrefixes ) Gets the display name for a namespace after removing its family segment. Parameters fullNamespace The full namespace to simplify. namespacePrefixes Prefixes that may be removed before display extraction. Returns The namespace remainder after the family segment, or the simplified namespace when no remainder exists. Method SimplifyNamespace string SimplifyNamespace ( string fullNamespace , IReadOnlyList\u003Cstring\u003E namespacePrefixes ) Removes the first matching configured namespace prefix from a namespace. Parameters fullNamespace The namespace to simplify. Blank values become Namespaces . namespacePrefixes Candidate prefixes, with optional trailing dots. Returns The simplified namespace, the last prefix segment for exact prefix matches, or the original namespace. Method GetDerivedNamespacePrefixes string[] GetDerivedNamespacePrefixes ( IEnumerable\u003CDocNode\u003E docs ) Derives shared namespace prefixes from the root namespace pages in a docs set. Parameters docs The harvested documentation nodes. Returns The shared prefix with and without trailing dot, or an empty array when no common prefix exists. Method GetLastNamespaceSegment string GetLastNamespaceSegment ( string namespaceValue ) Gets the last segment of a namespace value. Parameters namespaceValue A dot-delimited namespace value. Returns The segment after the last dot, or the original value when no dot exists. Type DocSectionDisplayBuilder Shapes public-section snapshots into the grouped link structures used by section pages and the shared sidebar. Method BuildGroups IReadOnlyList\u003CDocSectionGroupViewModel\u003E BuildGroups ( DocSectionSnapshot snapshot , string? currentHref = null , IReadOnlyList\u003Cstring\u003E? namespacePrefixes = null , string docsRootPath = \u0022/docs\u0022 ) Builds grouped section links for one public section snapshot. Parameters snapshot The public-section snapshot to group for display. currentHref The current docs href, if known. When provided, matching links are marked current for accessibility and styling. namespacePrefixes Optional namespace prefixes used to shorten API-reference labels and family headings. When omitted, API-reference groups derive prefixes from the visible pages in snapshot . docsRootPath The app-relative docs root path used to build canonical links for the current surface. Returns The grouped link model for the supplied section snapshot. Remarks Editorial sections stay flat and task-oriented, while DocPublicSection.ApiReference delegates to the namespace-aware grouping path so API reference content stays organized by family. API-reference groups intentionally omit generated type-anchor children from these global navigation models, and deeper namespace children are nested under their nearest useful parent so repeated namespace prefixes do not dominate the primary sidebar. Readers reach type and member anchors from the namespace page\u0027s local outline, source links, or search instead of loading every symbol into the primary sidebar.","snippet":"Type SidebarViewComponent A view component that renders the sidebar navigation for public documentation sections. Remarks The component returns a DocSidebarViewModel whose DocSidebarViewModel.Sections contain...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","ViewComponents"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html#ForgeTrust-AppSurface-Docs-ViewComponents-DocSectionDisplayBuilder","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html#ForgeTrust-AppSurface-Docs-ViewComponents-DocSectionDisplayBuilder","title":"DocSectionDisplayBuilder","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","ViewComponents","DocSectionDisplayBuilder"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents#ForgeTrust-AppSurface-Docs-ViewComponents-DocSectionDisplayBuilder"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html#ForgeTrust-AppSurface-Docs-ViewComponents-SidebarDisplayHelper","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html#ForgeTrust-AppSurface-Docs-ViewComponents-SidebarDisplayHelper","title":"SidebarDisplayHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","ViewComponents","SidebarDisplayHelper"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents#ForgeTrust-AppSurface-Docs-ViewComponents-SidebarDisplayHelper"},{"id":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html#ForgeTrust-AppSurface-Docs-ViewComponents-SidebarViewComponent","path":"/docs/Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents.html#ForgeTrust-AppSurface-Docs-ViewComponents-SidebarViewComponent","title":"SidebarViewComponent","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorDocs","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Docs","ViewComponents","SidebarViewComponent"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Docs.ViewComponents#ForgeTrust-AppSurface-Docs-ViewComponents-SidebarViewComponent"},{"id":"Namespaces/ForgeTrust.AppSurface.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.html","title":"AppSurface","summary":"Namespaces Aspire Caching Cli Config Console Core Dependency Docs MarkdownSnippets PackageIndex Web","headings":[],"bodyText":"Namespaces Aspire Caching Cli Config Console Core Dependency Docs MarkdownSnippets PackageIndex Web","snippet":"Namespaces Aspire Caching Cli Config Console Core Dependency Docs MarkdownSnippets PackageIndex Web","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"AppSurface","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface"],"sourcePath":"Namespaces/ForgeTrust.AppSurface"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html","title":"MarkdownSnippets","summary":"Type Program Method Main Task\u003Cint\u003E Main ( string[] args ) Process entry point that runs the CLI against the current working directory. Parameters args Command-line arguments passed by the host process. Returns The...","headings":["Program","Main","RunAsync","IsHelp","MarkdownSnippetCommandOptions","Parse","ReadRequiredValue","ResolvePath","MarkdownSnippetRequest","GetRepositoryRelativeDocumentPath","MarkdownSnippetGenerator","GenerateToFileAsync","GenerateAsync","VerifyAsync","ValidateRequest","MarkdownSnippetRewriter","Rewrite","ParseBlock","ParseAttributes","ValidateAttributeNames","ReadRequiredAttribute","ReadBooleanAttribute","ValidateId","ValidateLanguage"],"bodyText":"Type Program Method Main Task\u003Cint\u003E Main ( string[] args ) Process entry point that runs the CLI against the current working directory. Parameters args Command-line arguments passed by the host process. Returns The process exit code. Method RunAsync Task\u003Cint\u003E RunAsync ( string[] args , TextWriter standardOut , TextWriter standardError , string currentDirectory , CancellationToken cancellationToken = default ) Runs the Markdown snippet CLI command contract. Parameters args Command-line arguments. The first argument must be generate , verify , --help , or -h . Command options after generate or verify are parsed by MarkdownSnippetCommandOptions.Parse . standardOut Destination for help and successful command output. standardError Destination for validation and command failure output. currentDirectory Working directory used for option defaults. When --repo-root is omitted, this becomes the repository root; when --document is omitted, the default document is Web/ForgeTrust.RazorWire/README.md under that root. cancellationToken Cancellation token for file IO. Returns 0 for success or help, 1 for invalid input or stale snippets. Remarks Relative --repo-root values resolve from currentDirectory ; relative --document values resolve from the resolved repository root. Unknown commands, unknown options, missing option values, invalid snippet directives, unsafe paths, and stale generated blocks are reported as 1 with actionable error text rather than escaping as unhandled exceptions. Method IsHelp bool IsHelp ( string argument ) Determines whether an argument requests command help. Parameters argument Argument to inspect. Returns true for --help or -h . Type MarkdownSnippetCommandOptions Method Parse MarkdownSnippetCommandOptions Parse ( string[] args , string currentDirectory ) Parses command options into a repository/document request. Parameters args Only --repo-root \u003Cpath\u003E and --document \u003Cpath\u003E are supported. currentDirectory Current working directory used by omitted or relative --repo-root . Returns Parsed options with full repository and document paths. Exceptions MarkdownSnippetException Thrown when an option is unknown or a required option value is missing. Remarks The default repository root is currentDirectory . The default document is Web/ForgeTrust.RazorWire/README.md under the resolved repository root. A rooted --document is allowed at parse time but later rejected by generation/verification when it is outside the repository. Method ReadRequiredValue string ReadRequiredValue ( string[] args , ref int index , string argument ) Reads the required value immediately following an option name. Parameters args Complete option argument array. index Current option index, advanced to the value index on success. argument Option name for diagnostics. Returns The raw option value. Exceptions MarkdownSnippetException Thrown when the option has no following non-blank value or the next token looks like another option. Method ResolvePath string ResolvePath ( string? value , string baseDirectory , string defaultPath ) Resolves a rooted, relative, or omitted path to a full path. Parameters value Optional user-provided path. baseDirectory Directory used for relative values. defaultPath Path used when value is omitted. Returns A canonical full path. Type MarkdownSnippetRequest Method GetRepositoryRelativeDocumentPath string GetRepositoryRelativeDocumentPath () Gets the document path relative to RepositoryRoot with forward slashes for stable diagnostics and CLI output. Returns The repository-relative document path. Remarks Request validation ensures the document stays under the repository root before generation or verification uses this value for user-facing messages. Type MarkdownSnippetGenerator Method GenerateToFileAsync Task GenerateToFileAsync ( MarkdownSnippetRequest request , CancellationToken cancellationToken = default ) Generates the canonical Markdown document and writes it back to disk. Parameters request Repository root and Markdown document to update. cancellationToken Cancellation token for file IO. Exceptions MarkdownSnippetException Thrown when the repository/document path is invalid or snippet extraction fails. Method GenerateAsync Task\u003Cstring\u003E GenerateAsync ( MarkdownSnippetRequest request , CancellationToken cancellationToken = default ) Generates the canonical Markdown text for all managed snippet blocks. Parameters request Repository root and Markdown document to read. cancellationToken Cancellation token for file IO. Returns The rewritten Markdown document with \\n line endings. Exceptions MarkdownSnippetException Thrown when the document has no managed blocks, a block is malformed, a source path escapes the repository, markers are missing or duplicated, or extracted snippet content is empty. Remarks Generation is the mutating workflow used by maintainers after source sample changes. It normalizes document line endings and replaces only managed blocks outside existing Markdown code fences. Method VerifyAsync Task VerifyAsync ( MarkdownSnippetRequest request , CancellationToken cancellationToken = default ) Verifies that the checked-in Markdown already matches generated output. Parameters request Repository root and Markdown document to verify. cancellationToken Cancellation token for file IO. Exceptions MarkdownSnippetException Thrown when validation fails or the checked-in Markdown is stale. Remarks Verification is the CI workflow. It compares canonical generated text to the current document after normalizing line endings, so CRLF checkouts do not fail solely because of platform line-ending conversion. Method ValidateRequest void ValidateRequest ( MarkdownSnippetRequest request ) Validates repository/document existence and document containment. Parameters request Request to validate before source files are read. Exceptions MarkdownSnippetException Thrown when the repository root is missing, the document is missing, or the document is outside the repository root. Type MarkdownSnippetRewriter Rewrites managed \u003C!-- appsurface:snippet ... --\u003E blocks in Markdown. Remarks A managed block must contain an opening directive, a generated fenced code block, and the exact closing directive \u003C!-- /appsurface:snippet --\u003E . Directives are ignored inside existing Markdown code fences, and the managed closing directive is only recognized outside the generated block\u0027s code fence. Supported attributes are id , file , marker , lang , and optional dedent . Attributes must use quoted name=\u0022value\u0022 syntax. file is repository-relative; rooted paths and .. escapes fail before source files are read. dedent defaults to true , which removes common indentation from extracted non-blank source lines. Method Rewrite string Rewrite ( MarkdownSnippetRequest request , string markdown ) Rewrites managed snippet blocks and returns canonical Markdown. Parameters request Repository root and document path used for path resolution and diagnostics. markdown Original Markdown text. Returns Markdown with generated blocks rendered using \\n line endings. Exceptions MarkdownSnippetException Thrown when no managed blocks are present, a directive is malformed, a source file is unsafe or missing, markers are invalid, or a block is not closed. Method ParseBlock MarkdownSnippetBlock ParseBlock ( MarkdownSnippetRequest request , string[] lines , ref int index ) Parses one managed snippet block and extracts its replacement content. Parameters request Repository/document request for path resolution and diagnostics. lines Normalized Markdown lines. index Current opening-line index, advanced to the managed closing line. Returns The parsed block with source-backed content. Exceptions MarkdownSnippetException Thrown when attributes are invalid, the source file path is unsafe, source markers are invalid, or the managed block is missing its closing directive. Method ParseAttributes Dictionary\u003Cstring, string\u003E ParseAttributes ( string openingLine , string documentPath , int lineNumber ) Parses and validates quoted directive attributes from an opening line. Exceptions MarkdownSnippetException Thrown for missing --\u003E , duplicate attributes, unsupported attribute syntax, empty attribute sets, or unknown attribute names. Method ValidateAttributeNames void ValidateAttributeNames ( IReadOnlyDictionary\u003Cstring, string\u003E attributes , string documentPath , int lineNumber ) Ensures all directive attribute names are supported by the snippet contract. Parameters attributes Parsed directive attributes. documentPath Repository-relative document path for diagnostics. lineNumber One-based directive line number. Exceptions MarkdownSnippetException Thrown when any attribute name is unknown. Method ReadRequiredAttribute string ReadRequiredAttribute ( IReadOnlyDictionary\u003Cstring, string\u003E attributes , string name , MarkdownSnippetRequest request , int lineNumber ) Reads a required directive attribute and trims its value. Exceptions MarkdownSnippetException Thrown when the attribute is missing or blank. Method ReadBooleanAttribute bool ReadBooleanAttribute ( IReadOnlyDictionary\u003Cstring, string\u003E attributes , string name , bool defaultValue , MarkdownSnippetRequest request , int lineNumber ) Reads an optional boolean directive attribute. Exceptions MarkdownSnippetException Thrown when the value is not a valid boolean. Remarks dedent uses this helper with a default of true . Only true and false values accepted by the platform boolean parser are valid. Method ValidateId void ValidateId ( string value , string description , MarkdownSnippetRequest request , int lineNumber ) Validates a snippet id or source marker id. Parameters value Candidate id. description Diagnostic description of the id role. request Request used to name the document in diagnostics. lineNumber One-based directive line number. Exceptions MarkdownSnippetException Thrown when the id uses unsupported characters. Method ValidateLanguage void ValidateLanguage ( string language , MarkdownSnippetRequest request , int lineNumber ) Validates the Markdown code fence language token. Parameters language Candidate language token. request Request used to name the document in diagnostics. lineNumber One-based directive line number. Exceptions MarkdownSnippetException Thrown when the language token contains unsupported characters. Method FindClosingLine int FindClosingLine ( string[] lines , int startIndex , MarkdownSnippetRequest request , string id ) Finds the managed block closing directive while ignoring text inside Markdown fences. Parameters lines Normalized Markdown lines. startIndex Line index immediately after the opening directive. request Request used to name the document in diagnostics. id Snippet id for diagnostics. Returns The line index containing \u003C!-- /appsurface:snippet --\u003E . Exceptions MarkdownSnippetException Thrown when no compatible closing directive is found. Method AppendLine void AppendLine ( StringBuilder builder , string line , int index , int lineCount ) Appends one original Markdown line while preserving the canonical final newline shape. Parameters builder Destination builder. line Line text without its newline. index Current line index. lineCount Total line count. Type MarkdownCodeFence Method TryParse MarkdownCodeFence? TryParse ( string trimmedLine ) Parses a Markdown code fence opener or closer. Parameters trimmedLine Line trimmed of surrounding whitespace. Returns A fence when the line begins with at least three backticks or tildes; otherwise null . Method IsClosedBy bool IsClosedBy ( string trimmedLine ) Determines whether a trimmed line closes this fence. Parameters trimmedLine Line trimmed of surrounding whitespace. Returns true when the line uses the same fence character, has length at least as long as the opener, and contains only that fence character. Type MarkdownSnippetBlock Method Render string Render () Renders a managed block using an automatically sized backtick fence. Returns The complete managed block with \\n line endings. Remarks The fence is one backtick longer than the longest backtick run in the content, with a minimum length of three, so nested Markdown examples stay literal inside the generated block. Type MarkdownSnippetSourceExtractor Extracts source snippets between exact documentation marker lines. Remarks Supported marker forms are delegated to MarkdownSnippetMarker : C# line comments, Razor comments, and HTML comments. A marker pair must be unique, ordered as :start then :end , and contain at least one non-blank line. Marker-like text in strings or inline comments is ignored because markers must occupy the whole trimmed line. When dedent is enabled, common leading spaces or tabs across non-blank snippet lines are removed and surrounding blank lines are trimmed. Method Extract string Extract ( string source , string markerId , string sourcePath , bool dedent ) Extracts and optionally dedents the snippet for a marker id. Parameters source Source file text. markerId Marker id without :start or :end . sourcePath Repository-relative source path for diagnostics. dedent Whether to remove common indentation from extracted lines. Returns Extracted snippet content with \\n line endings. Exceptions MarkdownSnippetException Thrown when start/end markers are missing, duplicated, reversed, or enclose only blank content. Method Dedent string Dedent ( string[] lines ) Removes common indentation from snippet lines. Parameters lines Snippet lines between markers. Returns Dedented snippet text with surrounding blank lines trimmed. Remarks Only non-blank lines contribute to the minimum indent. Indentation counts both spaces and tabs as one character because snippets preserve source text rather than reformatting it. Method CountIndent int CountIndent ( string line ) Counts leading spaces and tabs on a source line. Parameters line Line to inspect. Returns The number of leading indentation characters. Type MarkdownSnippetMarker Method IsValidId bool IsValidId ( string value ) Determines whether a snippet id is safe for marker and directive use. Parameters value Candidate id. Returns true when the id starts with an ASCII letter or digit and then uses only letters, digits, _ , - , or . . Method TryParse MarkdownSnippetMarkerKind TryParse ( string line , string markerId ) Parses a whole-line source snippet marker. Parameters line Source line to inspect. A UTF-8 BOM on the first line is ignored. markerId Expected marker id. Returns The marker kind, or MarkdownSnippetMarkerKind.None . Remarks Valid marker forms are exactly // docs:snippet id:start , @* docs:snippet id:start *@ , and \u003C!-- docs:snippet id:start --\u003E , with matching :end variants. Whitespace may surround the whole line but not the inner marker text. Method IsMarker bool IsMarker ( string trimmed , string markerId , string markerKind ) Matches one exact marker form for a marker id and kind. Parameters trimmed Source line trimmed of surrounding whitespace and any leading BOM. markerId Expected marker id. markerKind Expected marker kind, usually start or end . Returns true when the line is an exact supported comment marker. Type MarkdownFence Method Create string Create ( string content ) Creates a Markdown backtick fence that safely contains the supplied content. Parameters content Snippet content to wrap. Returns At least three backticks, or one more than the longest run in content . Type MarkdownSnippetPath Method ResolveRepositoryFilePath string ResolveRepositoryFilePath ( string repositoryRoot , string repositoryRelativePath , string description ) Resolves a repository-relative source file path and enforces repository containment. Parameters repositoryRoot Repository root directory. repositoryRelativePath Source path from a snippet directive. description Human-readable path description for diagnostics. Returns The full source file path. Exceptions MarkdownSnippetException Thrown when the path is rooted, escapes the repository root, or points to a missing file. Remarks Snippet file attributes must be repository-relative so generated documentation is portable across machines and CI checkouts. Method TryGetRepositoryRelativePath bool TryGetRepositoryRelativePath ( string repositoryRoot , string path , out string relativePath ) Converts a path to a repository-relative path when it is safely contained in the repository. Parameters repositoryRoot Repository root directory. path Candidate full or relative path. relativePath Repository-relative path with forward slashes when successful. Returns true when path is inside repositoryRoot , is not the root itself, and does not cross a reparse-point segment. Remarks The containment check starts with lexical path normalization, then walks the repository-relative path segments and rejects symlinks or other reparse points before file IO can follow them outside the repository. Method ContainsReparsePointSegment bool ContainsReparsePointSegment ( string fullRoot , string relativePath ) Determines whether any existing path segment below the repository root is a reparse point. Parameters fullRoot Canonical repository root path. relativePath Repository-relative candidate path with forward slashes. Returns true when an inspected segment is a symlink or other reparse point.","snippet":"Type Program Method Main Task\u003Cint\u003E Main ( string[] args ) Process entry point that runs the CLI against the current working directory. Parameters args Command-line arguments passed by the host process. Returns The...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownCodeFence","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownCodeFence","title":"MarkdownCodeFence","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownCodeFence"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownCodeFence"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownFence","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownFence","title":"MarkdownFence","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownFence"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownFence"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetBlock","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetBlock","title":"MarkdownSnippetBlock","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetBlock"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetBlock"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetCommandOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetCommandOptions","title":"MarkdownSnippetCommandOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetCommandOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetCommandOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetGenerator","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetGenerator","title":"MarkdownSnippetGenerator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetGenerator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetGenerator"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetMarker","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetMarker","title":"MarkdownSnippetMarker","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetMarker"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetMarker"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetPath","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetPath","title":"MarkdownSnippetPath","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetPath"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetPath"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetRequest","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetRequest","title":"MarkdownSnippetRequest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetRequest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetRequest"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetRewriter","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetRewriter","title":"MarkdownSnippetRewriter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetRewriter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetRewriter"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetSourceExtractor","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetSourceExtractor","title":"MarkdownSnippetSourceExtractor","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","MarkdownSnippetSourceExtractor"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-MarkdownSnippetSourceExtractor"},{"id":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-Program","path":"/docs/Namespaces/ForgeTrust.AppSurface.MarkdownSnippets.html#ForgeTrust-AppSurface-MarkdownSnippets-Program","title":"Program","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"MarkdownSnippets","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","MarkdownSnippets","Program"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.MarkdownSnippets#ForgeTrust-AppSurface-MarkdownSnippets-Program"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html","title":"PackageIndex","summary":"Type PackageIndexGenerator Generates and verifies the manifest-backed package chooser markdown for the repository. Remarks This generator is intentionally repository-aware. It expects the manifest, chooser sidecar,...","headings":["PackageIndexGenerator","GenerateToFileAsync","GenerateAsync","VerifyAsync","RunPackageGateAsync","RepositoryPathComparison","PackageIndexRequest","ResolvedPackageEntry","PackageGateReport","PackageGateValidator","Validate","PackageIndexException","IProjectMetadataProvider","GetMetadataAsync","PackageProjectMetadata","InstallCommand","PackageProjectScanner","DiscoverProjects","IsCandidateProject","DotNetProjectMetadataProvider","ParseMetadataJson","PackageManifestLoader","LoadAsync","PackageManifest"],"bodyText":"Type PackageIndexGenerator Generates and verifies the manifest-backed package chooser markdown for the repository. Remarks This generator is intentionally repository-aware. It expects the manifest, chooser sidecar, package README links, and release-surface links to resolve to files under the supplied repository root. Callers should validate repository layout drift through VerifyAsync in CI whenever package or docs paths change. Method GenerateToFileAsync Task GenerateToFileAsync ( PackageIndexRequest request , CancellationToken cancellationToken = default ) Generates chooser markdown and writes it to the configured output path. Parameters request Generation request describing the repository root, manifest path, and output path. cancellationToken Cancellation token used for manifest loading, metadata evaluation, and file writes. Returns A task that completes when the chooser file has been written. Exceptions PackageIndexException Thrown when the repository layout is invalid, required docs are missing, or the manifest cannot be rendered safely. Remarks This method creates the output directory when it does not already exist and overwrites the chooser file atomically from the generated markdown payload. Method GenerateAsync Task\u003Cstring\u003E GenerateAsync ( PackageIndexRequest request , CancellationToken cancellationToken = default ) Generates chooser markdown from the manifest and evaluated project metadata without writing it to disk. Parameters request Generation request describing the repository root, manifest path, and output path context. cancellationToken Cancellation token used while loading the manifest and project metadata. Returns The fully rendered chooser markdown. Exceptions PackageIndexException Thrown when repository layout, manifest content, or linked docs targets do not satisfy the chooser contract. Method VerifyAsync Task VerifyAsync ( PackageIndexRequest request , CancellationToken cancellationToken = default ) Verifies that the checked-in chooser file matches the current repository truth. Parameters request Verification request describing the repository root, manifest path, and generated chooser file. cancellationToken Cancellation token used while regenerating and reading the existing chooser file. Returns A task that completes when verification succeeds. Exceptions PackageIndexException Thrown when the generated chooser is missing or differs from the freshly generated markdown. Method RunPackageGateAsync Task\u003CPackageGateReport\u003E RunPackageGateAsync ( PackageIndexRequest request , CancellationToken cancellationToken = default ) Runs release-readiness checks that protect the package manifest from drifting away from publishable packages. Parameters request Gate request describing the repository root, manifest path, and generated chooser file. cancellationToken Cancellation token used while evaluating package metadata and scanning files. Returns A report summarizing the package and source-file surfaces covered by the gate. Exceptions PackageIndexException Thrown when release metadata is missing, package class rules are violated, or stale brand strings remain. Property RepositoryPathComparison StringComparison RepositoryPathComparison { get; } Gets the path-comparison rule used when enforcing repository-boundary checks for chooser links. Remarks Windows paths are treated case-insensitively. Other platforms stay ordinal so chooser validation does not assume a case-insensitive filesystem on Linux or macOS. Type PackageIndexRequest Describes one package chooser generation or verification request. Parameters RepositoryRoot Absolute repository root that contains the manifest, docs, and project files. ManifestPath Absolute path to the chooser manifest file. OutputPath Absolute path to the generated chooser markdown file. Type ResolvedPackageEntry Couples one manifest row with the evaluated package metadata used to render the chooser. Parameters Manifest The manifest row that provides classification, prose, and docs pointers. Metadata The evaluated project metadata that provides package identity and install details. Type PackageGateReport Summarizes the package gate coverage used by CI and local release checks. Parameters PackageCount Number of manifest entries validated by package class and release metadata rules. ScannedFileCount Number of source files scanned for stale brand strings. Type PackageGateValidator Validates package release metadata, package-class invariants, and stale brand drift before packages are published. Method Validate PackageGateReport Validate ( string repositoryRoot , IReadOnlyList\u003CResolvedPackageEntry\u003E entries ) Validates all gate rules against resolved package entries and repository files. Parameters repositoryRoot Absolute repository root to scan. entries Resolved package entries from the chooser manifest. Returns A compact report describing gate coverage. Type PackageIndexException Represents a package chooser generation or verification failure. Remarks These exceptions are written directly to CLI stderr, so messages should stay actionable and user-facing. Type IProjectMetadataProvider Contract for evaluating one discovered project into package metadata suitable for chooser rendering. Method GetMetadataAsync Task\u003CPackageProjectMetadata\u003E GetMetadataAsync ( string repositoryRoot , string projectPath , CancellationToken cancellationToken ) Evaluates one project file and returns the package metadata used by the chooser. Parameters repositoryRoot Absolute repository root used as the evaluation working directory. projectPath Repository-relative project path for the project being evaluated. cancellationToken Cancellation token that should abort the evaluation when possible. Returns The evaluated project metadata for the supplied project. Type PackageProjectMetadata Evaluated package metadata used by the chooser renderer. Parameters ProjectPath Repository-relative path to the project that produced this metadata. PackageId NuGet package identifier emitted by the project. TargetFramework Resolved target framework summary used in chooser copy. IsPackable Whether the project reports itself as packable. IsTool Whether the project reports itself as a .NET tool package. OutputType Resolved output type, such as Library or Exe . ProjectReferences Evaluated project reference paths reported by MSBuild. Property InstallCommand string InstallCommand { get; } Gets the primary install command shown in the chooser for this package or tool. Type PackageProjectScanner Discovers candidate projects that should be classified by the package chooser manifest. Remarks The scanner intentionally excludes tests, examples, tooling, and generated directories so the manifest only needs to classify packages that are meaningful to external adopters or package-surface maintainers. Method DiscoverProjects IReadOnlyList\u003Cstring\u003E DiscoverProjects ( string repositoryRoot ) Enumerates candidate project files under the repository root. Parameters repositoryRoot Absolute repository root to scan. Returns Repository-relative project paths ordered for stable manifest validation. Method IsCandidateProject bool IsCandidateProject ( string relativePath ) Determines whether a repository-relative project path belongs in the chooser manifest. Parameters relativePath Repository-relative project path to evaluate. Returns true when the path should be classified by the chooser manifest; otherwise, false . Type DotNetProjectMetadataProvider Evaluates project metadata by invoking dotnet msbuild and reading JSON property output. Remarks This provider depends on a functioning local .NET SDK and assumes the project can be evaluated from the repository root. Timeouts and malformed output are surfaced as PackageIndexException so CLI callers can fail fast in CI. Method ParseMetadataJson PackageProjectMetadata ParseMetadataJson ( string projectPath , string standardOutput ) Parses one dotnet msbuild JSON payload into package metadata. Parameters projectPath Repository-relative project path used for error reporting. standardOutput Raw JSON payload captured from dotnet msbuild . Returns The normalized package metadata derived from the JSON payload. Exceptions PackageIndexException Thrown when the JSON payload is malformed, missing required properties, or reports incomplete metadata. Remarks This parsing seam is intentionally internal so tests can verify malformed and incomplete metadata handling without depending on a real SDK invocation or using reflection against private helpers. Type PackageManifestLoader Loads the chooser manifest from YAML into strongly typed manifest models. Method LoadAsync Task\u003CPackageManifest\u003E LoadAsync ( string manifestPath , CancellationToken cancellationToken ) Reads and parses the chooser manifest file. Parameters manifestPath Absolute path to the chooser manifest file. cancellationToken Cancellation token used while reading the manifest from disk. Returns The parsed chooser manifest. Exceptions PackageIndexException Thrown when the manifest cannot be parsed or does not define any package rows. Type PackageManifest Root manifest model for the chooser YAML file. Property Packages List\u003CPackageManifestEntry\u003E Packages { get; init; } Gets the ordered manifest rows that describe each package, support surface, or excluded package entry. Type PackageManifestEntry One manifest row describing how a project should appear in the chooser. Remarks Public rows must define install guidance and docs pointers. Non-public rows must define Note because their rendered bullets rely on that prose to explain why they are visible but not recommended as first installs. Property Project string Project { get; init; } Gets the repository-relative project path classified by this manifest entry. Property Classification PackageClassification Classification { get; init; } Gets the chooser classification that controls which section renders the package. Property PublishDecision PackagePublishDecision? PublishDecision { get; init; } Gets the publish decision consumed by the prerelease package artifact workflow. Property PublishReason string? PublishReason { get; init; } Gets the required maintainer-facing reason for entries that are intentionally not published. Property Order int Order { get; init; } Gets the stable display order within the chooser section. Property UseWhen string? UseWhen { get; init; } Gets the adopter-focused \u201Cuse when\u201D guidance for public package rows. Property Includes string? Includes { get; init; } Gets the concise statement describing what the package includes for public rows. Property DoesNotInclude string? DoesNotInclude { get; init; } Gets the concise statement describing what the package intentionally does not include for public rows. Property StartHerePath string? StartHerePath { get; init; } Gets the repository-relative documentation file linked from this chooser row. Property StartHereLabel string? StartHereLabel { get; init; } Gets the optional chooser label used for the linked documentation target. Property RecipeSummary string? RecipeSummary { get; init; } Gets the optional recipe summary shown in the \u201CAlso building...\u201D section. Property Note string? Note { get; init; } Gets the explanatory note rendered for non-public package rows. Property DependsOn List\u003Cstring\u003E DependsOn { get; init; } Gets the optional package ids that this row depends on for install guidance. Property ExpectedDependencyPackageIds List\u003Cstring\u003E ExpectedDependencyPackageIds { get; init; } Gets the exact package ids expected from project-reference dependencies in the produced package. Property ReleaseStatus PackageReleaseStatus ReleaseStatus { get; init; } Gets the release status expected by package-gate for this package classification. Property CommercialStatus PackageCommercialStatus CommercialStatus { get; init; } Gets whether this package row is part of the commercial-ready public surface. Property ReleaseNotesPath string? ReleaseNotesPath { get; init; } Gets the repository-relative release notes file that explains current readiness for this package. Enum PackageClassification Chooser section classifications for manifest entries. Enum PackagePublishDecision Publish decisions for package artifact verification and later prerelease publishing. Enum PackageReleaseStatus Release status values package-gate expects for each chooser classification. Enum PackageCommercialStatus Commercial readiness status values used by package-gate. Type PackageArtifactWorkflow Coordinates prerelease package artifact packing and validation without publishing to NuGet. Method RunAsync Task\u003CPackageArtifactValidationReport\u003E RunAsync ( PackageArtifactRequest request , CancellationToken cancellationToken = default ) Packs and validates prerelease package artifacts. Parameters request Artifact workflow request. cancellationToken Cancellation token propagated to external commands and file writes. Returns Successful validation report. Type PackageArtifactRequest Request for package artifact packing and validation. Parameters RepositoryRoot Absolute repository root. ManifestPath Absolute package manifest path. ArtifactsOutputPath Directory that receives produced .nupkg artifacts. ReportPath Markdown validation report path. PackageVersion Exact prerelease package version to pack and validate. ArtifactManifestPath Machine-readable validation manifest path for the publish workflow. Type CliWrapCommandRunner Runs external commands through CliWrap for protected package publishing and smoke-install workflows. Type IExternalCommandRunner External command runner used by publish and smoke workflows when non-zero exit codes are meaningful results. Method RunAsync Task\u003CExternalCommandResult\u003E RunAsync ( ExternalCommandRequest request , CancellationToken cancellationToken ) Runs a command and returns stdout, stderr, and exit code without throwing for non-zero exits. Parameters request Command request. cancellationToken Cancellation token. Returns Captured command result. Type ExternalCommandRequest Command invocation for CliWrap-backed release automation. Type ExternalCommandResult Captured command result including non-zero exit codes. Type PackageArtifactManifestWriter Writes the machine-readable package artifact manifest consumed by protected publish jobs. Method WriteAsync Task WriteAsync ( PackageArtifactValidationReport report , string artifactsDirectory , string manifestPath , CancellationToken cancellationToken ) Writes a manifest that binds validated package ids to artifact file names and SHA-512 hashes. Parameters report Package artifact validation report. artifactsDirectory Directory containing the validated package artifacts. manifestPath Destination manifest path. cancellationToken Cancellation token. Type PackageArtifactManifestReader Reads and validates the artifact manifest written by the package artifact verifier. Method ReadAsync Task\u003CPackageArtifactManifest\u003E ReadAsync ( string manifestPath , CancellationToken cancellationToken ) Reads a package artifact manifest from disk. Parameters manifestPath Manifest path. cancellationToken Cancellation token. Returns Validated artifact manifest. Type PackagePrereleasePublishWorkflow Publishes a validated prerelease package artifact set to NuGet in manifest order. Method RunAsync Task\u003CPackagePublishLedger\u003E RunAsync ( PackagePrereleasePublishRequest request , CancellationToken cancellationToken ) Publishes each artifact selected by the checked-in manifest and writes a markdown ledger. Parameters request Publish request. cancellationToken Cancellation token. Returns Publish ledger. Type PackageSmokeInstallWorkflow Restores published public packages from a clean NuGet configuration after publish completes. Method RunAsync Task\u003CPackageSmokeInstallReport\u003E RunAsync ( PackageSmokeInstallRequest request , CancellationToken cancellationToken ) Restores each public package from the configured package source in an isolated workspace. Parameters request Smoke install request. cancellationToken Cancellation token. Returns Smoke install report. Type PackagePublishLedgerRenderer Renders protected publish outcomes for workflow artifacts. Type PackageSmokeInstallReportRenderer Renders package smoke install outcomes for workflow artifacts. Type PackagePrereleasePublishRequest Request for the protected NuGet prerelease publish workflow. Parameters RepositoryRoot Repository root used for plan resolution. ManifestPath Checked-in package manifest path. ArtifactsInputPath Directory containing validated .nupkg files. ArtifactManifestPath Machine-readable artifact manifest path. PublishLogPath Markdown publish ledger path. Source NuGet source URL. ApiKeyEnvironmentVariable Environment variable that supplies the NuGet API key. Type PackageSmokeInstallRequest Request for the post-publish smoke install workflow. Parameters RepositoryRoot Repository root used for path display and validation. ManifestPath Checked-in package manifest path used to revalidate the artifact manifest. ArtifactManifestPath Machine-readable artifact manifest path. WorkDirectory Isolated smoke install work directory. ReportPath Markdown smoke install report path. Source NuGet source URL. Type PackageArtifactManifest Machine-readable artifact manifest that binds validated package artifacts to immutable hashes. Parameters SchemaVersion Manifest schema version. PackageVersion Exact prerelease package version. GeneratedAtUtc UTC timestamp when the manifest was generated. Entries Manifest entries in package publish order. Type PackageArtifactManifestEntry One package artifact selected from the checked-in package manifest. Parameters PackageId NuGet package id. ProjectPath Repository-relative project path. Decision Publish decision string from the package plan. ArtifactFileName Package artifact file name without directory segments. Sha512 Lowercase hexadecimal SHA-512 hash of the package artifact. IsTool Whether the artifact is a .NET tool package. Type PackagePublishLedger Publish result for a coordinated prerelease package version. Parameters PackageVersion Exact prerelease package version. Source NuGet source URL. Entries Per-package publish outcomes. Type PackagePublishLedgerEntry Publish outcome for one package artifact. Parameters PackageId NuGet package id. ProjectPath Repository-relative project path. ArtifactFileName Package artifact file name. Status Publish status. ExitCode Exit code from dotnet nuget push , or zero for skipped packages. Output Captured publish output with secrets excluded. Type PackageSmokeInstallReport Smoke install result for packages restored after prerelease publishing. Parameters PackageVersion Exact prerelease package version. Source NuGet source URL. Entries Per-package smoke install outcomes. Type PackageSmokeInstallReportEntry Smoke install outcome for one public package. Parameters PackageId NuGet package id. ProjectPath Repository-relative project path. IsTool Whether the package was installed as a .NET tool. Status Smoke install status. ExitCode Exit code from the final restore or tool install attempt. Output Captured install output. Type PackageHash Computes package artifact hashes for manifest generation and publish verification. Type PackageArtifactJson JSON serializer options shared by artifact manifest readers and writers. Type ReleaseEnvironment Environment variables that make release automation quieter and deterministic. Type PackagePublishDecisionFormatter Formats package publish decisions for machine-readable release artifacts. Type PackageArtifactManifestPlanValidator Verifies that an artifact manifest still matches the checked-in package plan and validated artifacts. Type PlannedPackageArtifact Package artifact that has been matched to both the checked-in plan and artifact manifest. Parameters ManifestEntry Manifest entry for the artifact. ArtifactPath Resolved artifact path on disk. Enum PackagePublishStatus Publish status values written to the protected publish ledger. Enum PackageSmokeInstallStatus Smoke install status values written to the smoke report. Type PackagePublishPlanResolver Resolves the checked-in package manifest into the exact package set that should be packed. Method ResolveAsync Task\u003CPackagePublishPlan\u003E ResolveAsync ( string repositoryRoot , string manifestPath , CancellationToken cancellationToken ) Resolves and validates the package publish plan. Parameters repositoryRoot Absolute repository root. manifestPath Absolute path to the package manifest. cancellationToken Cancellation token used while loading metadata. Returns The ordered package publish plan. Type PackagePublishPlan Ordered package set selected for artifact packing and validation. Parameters Entries Packages that should be packed, in deterministic manifest order. Type PackagePublishPlanEntry One package selected for pack artifact production. Parameters ProjectPath Repository-relative project path to pack. PackageId Expected NuGet package id. Decision Publish decision from the manifest. ExpectedDependencyPackageIds Expected same-version package dependencies. IsTool Whether the package is a .NET tool package. Type PackageArtifactValidator Validates prerelease package artifacts against the resolved publish plan. Method Validate PackageArtifactValidationReport Validate ( PackagePublishPlan plan , string artifactsDirectory , string packageVersion ) Validates the package output directory and returns a markdown-ready report. Parameters plan Resolved package publish plan. artifactsDirectory Directory containing produced .nupkg files. packageVersion Exact package version expected in every artifact. Returns A validation report for the inspected artifacts. Type PackageArtifactReportRenderer Renders package artifact validation results for workflow artifacts. Method RenderMarkdown string RenderMarkdown ( PackageArtifactValidationReport report ) Renders the validation report as markdown. Parameters report Validation report to render. Returns Markdown report content. Type PackageVersionValidator Ensures package versions used by the prerelease workflow are safe for NuGet identity. Method RequirePrerelease void RequirePrerelease ( string packageVersion ) Validates that the package version is a prerelease SemVer identity without build metadata. Parameters packageVersion Package version to validate. Type PackageArtifactValidationReport Result of a successful package artifact validation run. Parameters PackageVersion Exact package version inspected. Entries Validated package report rows. Type PackageArtifactValidationReportEntry One validated package row in the artifact report. Parameters PackageId Validated package id. ProjectPath Project that produced the package. Decision Publish decision from the manifest. ExpectedDependencyPackageIds Expected same-version package dependency ids. ArtifactPath Validated .nupkg artifact path. IsTool Whether the package is a .NET tool package. Type InspectedPackage Metadata and payload facts inspected from one NuGet package artifact. Parameters PackagePath Absolute or caller-supplied path to the inspected .nupkg file. PackageId Nuspec package id. Expected to be non-empty after inspection. PackageVersion Nuspec package version. Expected to be non-empty after inspection. Authors Nuspec authors metadata, or null when absent. Description Nuspec description metadata, or null when absent. License Nuspec license expression or value, or null when absent. RepositoryUrl Nuspec repository URL, or null when absent. Tags Nuspec package tags, or null when absent. Readme Nuspec README path, or null when absent. PackageTypes Declared nuspec package type names such as DotnetTool . Dependencies Dependency ids mapped to all distinct nuspec versions observed across dependency groups. EntryPaths Normalized archive entry paths contained in the package. FirstPartyAssemblyVersions First-party implementation assemblies and their informational versions. Type InspectedAssemblyVersion Informational version metadata read from a first-party assembly inside a package artifact. Parameters EntryPath Archive path for the inspected assembly entry. InformationalVersion Assembly informational version value read from metadata. Type ICommandRunner Runs external commands for repository validation workflows. Method RunAsync Task\u003CCommandRunResult\u003E RunAsync ( CommandRunRequest request , CancellationToken cancellationToken ) Runs the requested command and returns captured output when it exits successfully. Parameters request Command request with process, timeout, and user-facing error context. cancellationToken Cancellation token used while waiting for command completion. Returns Captured process output. Exceptions PackageIndexException Thrown when the process fails to start, times out, or exits unsuccessfully. Type CommandRunRequest Describes one external command invocation and the language to use when it fails. Parameters FileName Executable name or path. Arguments Command-line arguments supplied without shell interpolation. WorkingDirectory Working directory for the process. OperationName Human-readable operation name, such as dotnet pack . Subject Repository item being processed, such as a project path. FailureVerb Verb phrase used in nonzero exit messages, such as pack or evaluate . TimeoutDescription Gerund phrase used in timeout messages, such as packing . TimeoutMilliseconds Timeout applied to the process wait. Environment Optional environment variable overrides. Type CommandRunResult Captured stdout and stderr from a successful command. Parameters StandardOutput Captured standard output. StandardError Captured standard error. Type ProcessCommandRunner Process-backed command runner with timeout and failure cleanup. Type Program CLI entry point for generating or verifying the package chooser. Method Main Task\u003Cint\u003E Main ( string[] args ) Launches the package chooser CLI with the current process IO streams and working directory. Parameters args Command-line arguments supplied to the process. Returns Process exit code where 0 indicates success. Method RunAsync Task\u003Cint\u003E RunAsync ( string[] args , TextWriter standardOut , TextWriter standardError , string currentDirectory , CancellationToken cancellationToken = default , Func\u003CPackageArtifactRequest, CancellationToken, Task\u003CPackageArtifactValidationReport\u003E\u003E? verifyPackagesAsync = null , Func\u003CPackagePrereleasePublishRequest, CancellationToken, Task\u003CPackagePublishLedger\u003E\u003E? publishPrereleaseAsync = null , Func\u003CPackageSmokeInstallRequest, CancellationToken, Task\u003CPackageSmokeInstallReport\u003E\u003E? smokeInstallAsync = null ) Runs the package chooser CLI against the supplied IO streams and working directory. Parameters args Command-line arguments, including the command and optional path overrides. If any help argument is present, this method returns usage output before command or option parsing so help remains available from any working directory. standardOut Writer that receives success messages and help/usage output. standardError Writer that receives invalid invocation usage and failure messages. currentDirectory Working directory used to resolve default repository-relative paths after help handling. cancellationToken Cancellation token propagated to generator operations. verifyPackagesAsync Optional package artifact workflow override used by tests. publishPrereleaseAsync Optional prerelease publish workflow override used by tests. smokeInstallAsync Optional smoke install workflow override used by tests. Returns 0 when the command succeeds; otherwise a non-zero exit code. Type CommandLineOptions Parsed CLI options for one package chooser command invocation. Parameters Request Resolved package chooser request derived from command-line options. ArtifactsOutputPath Resolved package artifact output directory. ReportPath Resolved package artifact validation report path. PackageVersion Optional package version supplied for package artifact verification. ArtifactsInputPath Resolved package artifact input directory for protected publish jobs. ArtifactManifestPath Resolved machine-readable package artifact manifest path. PublishLogPath Resolved protected publish ledger path. Source NuGet source URL used for publish and smoke install. ApiKeyEnvironmentVariable Environment variable name that supplies the NuGet API key. SmokeWorkDirectory Resolved isolated smoke install work directory. SmokeReportPath Resolved smoke install report path. Method Parse CommandLineOptions Parse ( string[] args , string currentDirectory ) Parses path-related CLI options into a resolved chooser request. Parameters args Arguments after the command verb. currentDirectory Working directory used to resolve relative overrides. Returns The parsed command-line options. Exceptions PackageIndexException Thrown when an option is unknown or missing its required value. Method CreatePackageArtifactRequest PackageArtifactRequest CreatePackageArtifactRequest () Converts parsed CLI options into a package artifact request. Returns The package artifact request. Exceptions PackageIndexException Thrown when the required package version is missing. Method CreatePackagePrereleasePublishRequest PackagePrereleasePublishRequest CreatePackagePrereleasePublishRequest () Converts parsed CLI options into a protected prerelease publish request. Returns The prerelease publish request. Method CreatePackageSmokeInstallRequest PackageSmokeInstallRequest CreatePackageSmokeInstallRequest () Converts parsed CLI options into a package smoke install request. Returns The package smoke install request.","snippet":"Type PackageIndexGenerator Generates and verifies the manifest-backed package chooser markdown for the repository. Remarks This generator is intentionally repository-aware. It expects the manifest, chooser sidecar,...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CliWrapCommandRunner","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CliWrapCommandRunner","title":"CliWrapCommandRunner","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","CliWrapCommandRunner"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-CliWrapCommandRunner"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CommandLineOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CommandLineOptions","title":"CommandLineOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","CommandLineOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-CommandLineOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CommandRunRequest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CommandRunRequest","title":"CommandRunRequest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","CommandRunRequest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-CommandRunRequest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CommandRunResult","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-CommandRunResult","title":"CommandRunResult","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","CommandRunResult"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-CommandRunResult"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-DotNetProjectMetadataProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-DotNetProjectMetadataProvider","title":"DotNetProjectMetadataProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","DotNetProjectMetadataProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-DotNetProjectMetadataProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ExternalCommandRequest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ExternalCommandRequest","title":"ExternalCommandRequest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","ExternalCommandRequest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-ExternalCommandRequest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ExternalCommandResult","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ExternalCommandResult","title":"ExternalCommandResult","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","ExternalCommandResult"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-ExternalCommandResult"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ICommandRunner","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ICommandRunner","title":"ICommandRunner","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","ICommandRunner"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-ICommandRunner"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-IExternalCommandRunner","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-IExternalCommandRunner","title":"IExternalCommandRunner","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","IExternalCommandRunner"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-IExternalCommandRunner"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-InspectedAssemblyVersion","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-InspectedAssemblyVersion","title":"InspectedAssemblyVersion","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","InspectedAssemblyVersion"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-InspectedAssemblyVersion"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-InspectedPackage","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-InspectedPackage","title":"InspectedPackage","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","InspectedPackage"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-InspectedPackage"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-IProjectMetadataProvider","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-IProjectMetadataProvider","title":"IProjectMetadataProvider","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","IProjectMetadataProvider"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-IProjectMetadataProvider"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactJson","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactJson","title":"PackageArtifactJson","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactJson"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactJson"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifest","title":"PackageArtifactManifest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactManifest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestEntry","title":"PackageArtifactManifestEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactManifestEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestPlanValidator","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestPlanValidator","title":"PackageArtifactManifestPlanValidator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactManifestPlanValidator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestPlanValidator"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestReader","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestReader","title":"PackageArtifactManifestReader","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactManifestReader"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestReader"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestWriter","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestWriter","title":"PackageArtifactManifestWriter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactManifestWriter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactManifestWriter"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactReportRenderer","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactReportRenderer","title":"PackageArtifactReportRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactReportRenderer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactReportRenderer"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactRequest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactRequest","title":"PackageArtifactRequest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactRequest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactRequest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidationReport","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidationReport","title":"PackageArtifactValidationReport","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactValidationReport"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidationReport"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidationReportEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidationReportEntry","title":"PackageArtifactValidationReportEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactValidationReportEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidationReportEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidator","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidator","title":"PackageArtifactValidator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactValidator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactValidator"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactWorkflow","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageArtifactWorkflow","title":"PackageArtifactWorkflow","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageArtifactWorkflow"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageArtifactWorkflow"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageClassification","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageClassification","title":"PackageClassification","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageClassification"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageClassification"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageCommercialStatus","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageCommercialStatus","title":"PackageCommercialStatus","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageCommercialStatus"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageCommercialStatus"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageGateReport","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageGateReport","title":"PackageGateReport","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageGateReport"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageGateReport"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageGateValidator","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageGateValidator","title":"PackageGateValidator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageGateValidator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageGateValidator"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageHash","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageHash","title":"PackageHash","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageHash"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageHash"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageIndexException","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageIndexException","title":"PackageIndexException","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageIndexException"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageIndexException"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageIndexGenerator","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageIndexGenerator","title":"PackageIndexGenerator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageIndexGenerator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageIndexGenerator"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageIndexRequest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageIndexRequest","title":"PackageIndexRequest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageIndexRequest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageIndexRequest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageManifest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageManifest","title":"PackageManifest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageManifest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageManifest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageManifestEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageManifestEntry","title":"PackageManifestEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageManifestEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageManifestEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageManifestLoader","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageManifestLoader","title":"PackageManifestLoader","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageManifestLoader"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageManifestLoader"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePrereleasePublishRequest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePrereleasePublishRequest","title":"PackagePrereleasePublishRequest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePrereleasePublishRequest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePrereleasePublishRequest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePrereleasePublishWorkflow","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePrereleasePublishWorkflow","title":"PackagePrereleasePublishWorkflow","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePrereleasePublishWorkflow"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePrereleasePublishWorkflow"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageProjectMetadata","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageProjectMetadata","title":"PackageProjectMetadata","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageProjectMetadata"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageProjectMetadata"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageProjectScanner","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageProjectScanner","title":"PackageProjectScanner","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageProjectScanner"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageProjectScanner"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishDecision","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishDecision","title":"PackagePublishDecision","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishDecision"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishDecision"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishDecisionFormatter","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishDecisionFormatter","title":"PackagePublishDecisionFormatter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishDecisionFormatter"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishDecisionFormatter"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedger","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedger","title":"PackagePublishLedger","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishLedger"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedger"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedgerEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedgerEntry","title":"PackagePublishLedgerEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishLedgerEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedgerEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedgerRenderer","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedgerRenderer","title":"PackagePublishLedgerRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishLedgerRenderer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishLedgerRenderer"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlan","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlan","title":"PackagePublishPlan","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishPlan"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlan"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlanEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlanEntry","title":"PackagePublishPlanEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishPlanEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlanEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlanResolver","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlanResolver","title":"PackagePublishPlanResolver","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishPlanResolver"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishPlanResolver"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishStatus","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackagePublishStatus","title":"PackagePublishStatus","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackagePublishStatus"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackagePublishStatus"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageReleaseStatus","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageReleaseStatus","title":"PackageReleaseStatus","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageReleaseStatus"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageReleaseStatus"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReport","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReport","title":"PackageSmokeInstallReport","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageSmokeInstallReport"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReport"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReportEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReportEntry","title":"PackageSmokeInstallReportEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageSmokeInstallReportEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReportEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReportRenderer","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReportRenderer","title":"PackageSmokeInstallReportRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageSmokeInstallReportRenderer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallReportRenderer"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallRequest","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallRequest","title":"PackageSmokeInstallRequest","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageSmokeInstallRequest"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallRequest"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallStatus","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallStatus","title":"PackageSmokeInstallStatus","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageSmokeInstallStatus"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallStatus"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallWorkflow","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallWorkflow","title":"PackageSmokeInstallWorkflow","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageSmokeInstallWorkflow"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageSmokeInstallWorkflow"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageVersionValidator","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PackageVersionValidator","title":"PackageVersionValidator","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PackageVersionValidator"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PackageVersionValidator"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PlannedPackageArtifact","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-PlannedPackageArtifact","title":"PlannedPackageArtifact","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","PlannedPackageArtifact"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-PlannedPackageArtifact"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ProcessCommandRunner","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ProcessCommandRunner","title":"ProcessCommandRunner","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","ProcessCommandRunner"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-ProcessCommandRunner"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-Program","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-Program","title":"Program","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","Program"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-Program"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ReleaseEnvironment","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ReleaseEnvironment","title":"ReleaseEnvironment","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","ReleaseEnvironment"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-ReleaseEnvironment"},{"id":"Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ResolvedPackageEntry","path":"/docs/Namespaces/ForgeTrust.AppSurface.PackageIndex.html#ForgeTrust-AppSurface-PackageIndex-ResolvedPackageEntry","title":"ResolvedPackageEntry","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"PackageIndex","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","PackageIndex","ResolvedPackageEntry"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.PackageIndex#ForgeTrust-AppSurface-PackageIndex-ResolvedPackageEntry"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html","title":"Web","summary":"Namespaces OpenApi Scalar Tailwind Type WebOptions Represents configuration options for the web application, including MVC, CORS, and static file settings. Property Mvc MvcOptions Mvc { get; set; } Gets or sets...","headings":["WebOptions","Mvc","Cors","StaticFiles","Errors","StartupTimeout","MapEndpoints","ErrorPagesOptions","UseConventionalBrowserStatusPages","DisableBrowserStatusPages","UseConventionalExceptionPage","DisableConventionalExceptionPage","AreConventionalBrowserStatusPagesEnabled","Default","BrowserStatusPageMode","ConventionalExceptionPageEnabled","ConventionalExceptionPageRenderer","ValidateConfiguredViews","RenderAsync","WebApp\u003CTStartup, TModule\u003E","RunAsync","WebApp\u003CTModule\u003E","ConventionalExceptionPageDefaults","BrowserStatusPageDefaults"],"bodyText":"Namespaces OpenApi Scalar Tailwind Type WebOptions Represents configuration options for the web application, including MVC, CORS, and static file settings. Property Mvc MvcOptions Mvc { get; set; } Gets or sets MVC-specific configuration options, such as support levels and custom MVC configuration. Property Cors CorsOptions Cors { get; set; } Gets or sets CORS configuration options for defining cross-origin resource sharing policies. Property StaticFiles StaticFilesOptions StaticFiles { get; set; } Gets or sets configuration options for serving static files within the web application. Property Errors ErrorPagesOptions Errors { get; set; } Gets or sets configuration options for conventional framework browser status pages. Remarks The default value is ErrorPagesOptions.Default , which leaves browser status pages in BrowserStatusPageMode.Auto . In that mode, AppSurface only enables the conventional browser 401, 403, and 404 experience when MVC support already includes views. Use explicit modes when an app must always force or always suppress the conventional pages. When enabled, AppSurface reserves /_appsurface/errors/401 , /_appsurface/errors/403 , and /_appsurface/errors/404 for direct rendering, and ignores that path prefix when deciding whether to apply browser-oriented status-page middleware. Static export tooling still consumes only the 404 route and writes only 404.html ; when CDN mode is active, that emitted page is validated and rewritten with the rest of the static graph. Property StartupTimeout TimeSpan? StartupTimeout { get; set; } Gets or sets the amount of time AppSurface waits for the web host to complete startup before failing fast. Remarks The default is 30 seconds. Set this to null only for hosts that intentionally perform long-running startup work before Kestrel binds. The watchdog covers pre-bind stalls caused by package layout, sandboxing, static asset discovery, hosted-service startup, and similar issues; it does not limit normal request processing after the host has started. StartupTimeout must be null or greater than TimeSpan.Zero . Use null to disable the watchdog instead of TimeSpan.Zero . Property MapEndpoints Action\u003CIEndpointRouteBuilder\u003E? MapEndpoints { get; set; } Gets or sets an optional delegate to configure endpoint routing for the application. Type ErrorPagesOptions Represents configuration options for AppSurface\u0027s conventional browser error pages. Remarks The default configuration keeps BrowserStatusPageMode at BrowserStatusPageMode.Auto , which enables conventional 401, 403, and 404 browser pages only when MVC support already includes Razor views. Apps that need the HTML status-page experience regardless of their starting MVC mode can opt into BrowserStatusPageMode.Enabled , while API-only or custom status-code handling stacks should use BrowserStatusPageMode.Disabled . Conventional production 500 pages are separate and always require an explicit call to UseConventionalExceptionPage . Method UseConventionalBrowserStatusPages void UseConventionalBrowserStatusPages () Explicitly enables AppSurface\u0027s conventional browser status pages. Remarks Use this when an app must always render the conventional HTML 401, 403, and 404 pages. AppSurface may effectively require controllers with views at startup so the configured Razor pages can execute. Method DisableBrowserStatusPages void DisableBrowserStatusPages () Explicitly disables AppSurface\u0027s conventional browser status pages. Remarks Use this for APIs, custom status-code middleware, or any app that wants to keep conventional browser status routes and handling out of the pipeline even when MVC view support is available. Method UseConventionalExceptionPage void UseConventionalExceptionPage () Explicitly enables AppSurface\u0027s conventional production exception page. Remarks Use this for browser-facing apps that want AppSurface to own the production 500 page through ASP.NET Core exception handling. The page renders only safe generic copy plus a request id, and AppSurface leaves Development behavior alone so developer exception diagnostics can remain active during local work. API-only apps or applications with custom exception middleware should leave this disabled and register their own handling before application endpoints. Method DisableConventionalExceptionPage void DisableConventionalExceptionPage () Explicitly disables AppSurface\u0027s conventional production exception page. Remarks Use this when a module enables the conventional exception page but the application host needs to supply a different exception-handling policy, such as JSON problem details, tenant-specific pages, or telemetry-first middleware. Method AreConventionalBrowserStatusPagesEnabled bool AreConventionalBrowserStatusPagesEnabled ( MvcSupport mvcSupportLevel ) Determines whether AppSurface should enable conventional browser status pages for the supplied MVC support level. Parameters mvcSupportLevel The MVC capability currently configured for the app. Returns true when the conventional page should be active; otherwise, false . Remarks This helper is used by AppSurface startup after module and app options are applied. In BrowserStatusPageMode.Auto , the feature only turns on when MVC already includes views. In BrowserStatusPageMode.Enabled , the feature is active regardless of the incoming MVC level because startup may upgrade the app to support Razor views. Property Default ErrorPagesOptions Default { get; } Gets a default instance of ErrorPagesOptions with BrowserStatusPageMode.Auto . Property BrowserStatusPageMode BrowserStatusPageMode BrowserStatusPageMode { get; set; } Gets or sets the conventional browser status page behavior for the application. Remarks BrowserStatusPageMode.Auto is the default and turns the feature on only when the app\u0027s MVC support reaches MvcSupport.ControllersWithViews . Choosing BrowserStatusPageMode.Enabled can cause AppSurface startup to upgrade MVC support so the conventional Razor views can render. Choosing BrowserStatusPageMode.Disabled prevents the reserved framework routes and browser-oriented status handling from activating. Property ConventionalExceptionPageEnabled bool ConventionalExceptionPageEnabled { get; set; } Gets or sets a value indicating whether AppSurface should render the conventional production exception page. Remarks The default is false so apps do not accidentally replace an existing exception-handling policy. Set this through UseConventionalExceptionPage when browser users should see a safe, generic HTML 500 page for unhandled exceptions in non-development environments. AppSurface uses ASP.NET Core\u0027s exception-handler middleware for this feature; status-code pages cannot catch thrown exceptions. Type ConventionalExceptionPageRenderer Resolves and renders AppSurface\u0027s conventional production exception page view. Remarks View resolution prefers ConventionalExceptionPageDefaults.AppViewPath first so apps and shared Razor Class Libraries can override the page conventionally. If that view is missing, the renderer falls back to ConventionalExceptionPageDefaults.FrameworkFallbackViewPath . The rendered model is deliberately small and safe: status code plus request id only. Method ValidateConfiguredViews void ValidateConfiguredViews () Performs eager validation of the configured conventional 500 view. Remarks Call this during startup to fail fast in production-like environments if neither the conventional app/shared view nor the framework fallback view can be resolved. Runtime rendering also resolves lazily, but this method turns a missing view into a predictable startup error instead of a request-time failure. Method RenderAsync Task RenderAsync ( HttpContext httpContext ) Renders the resolved conventional 500 view into the current HTTP response. Parameters httpContext The current request context used to build the model and execute the Razor view. Remarks This method sets the response status to 500 and passes only ExceptionPageModel to the view. It intentionally does not inspect IExceptionHandlerFeature or request data, so exception messages, stack traces, headers, cookies, route values, and form values cannot be disclosed through the default model. Enum BrowserStatusPageMode Controls how AppSurface applies its conventional browser-friendly status pages. Remarks Auto is the default and is the safest choice for most applications because it only enables the conventional pages when MVC view support is already available. Switch to Enabled when an app must always expose the conventional HTML 401, 403, and 404 experience, even if AppSurface needs to upgrade MVC support to controllers with views during startup. Use Disabled for API-first applications or when another status-code handling strategy should remain fully in control. The numeric values are explicit because this public enum may be persisted, serialized, or bound by applications. New values should be appended without changing the values documented here. Type WebApp\u003CTStartup, TModule\u003E Provides a static entry point for starting a web application with a custom startup class and root module. Type Parameters TStartup The type of the custom startup class, inheriting from WebStartup{TModule} . TModule The type of the root web module. Method RunAsync Task RunAsync ( string[] args , Action\u003CWebOptions\u003E? configureOptions = null ) Asynchronously runs the web application using the specified command-line arguments and optional option configuration. Parameters args The command-line arguments provided at application startup. configureOptions An optional delegate to further customize WebOptions during startup. Returns A Task representing the asynchronous operation of running the web application. Type WebApp\u003CTModule\u003E Provides a simplified static entry point for starting a web application using a default startup configuration. Type Parameters TModule The type of the root web module. Method RunAsync Task RunAsync ( string[] args , Action\u003CWebOptions\u003E? configureOptions = null ) Asynchronously runs the web application with a default startup using the specified command-line arguments and optional configuration. Parameters args The command-line arguments provided at application startup. configureOptions An optional delegate to customize WebOptions during startup. Returns A Task representing the asynchronous operation of running the web application. Type ConventionalExceptionPageDefaults Defines the conventional paths used by AppSurface\u0027s built-in browser-friendly production 500 handling. Type BrowserStatusPageDefaults Defines the conventional paths used by AppSurface\u0027s built-in browser-friendly status page handling. Remarks AppSurface owns browser status pages for 401, 403, and 404 responses in this release. Production exception pages, including conventional 500 handling, are intentionally separate because ASP.NET Core routes exceptions through exception-handling middleware instead of status-code pages. Method GetAppViewPath string GetAppViewPath ( int statusCode ) Formats the conventional app override view path for the supplied HTTP status code. Parameters statusCode The integer HTTP status code used for the view filename. AppSurface currently renders 401, 403, and 404. Returns The app/shared Razor view path produced from AppViewPathFormat . Remarks This helper does not validate support. Callers that accept arbitrary status codes should use BrowserStatusPageDescriptor.TryGet(int, out BrowserStatusPageDescriptor) before rendering. Method GetReservedRoute string GetReservedRoute ( int statusCode ) Formats the framework-reserved preview route for the supplied HTTP status code. Parameters statusCode The integer HTTP status code used for the reserved route segment. AppSurface currently renders 401, 403, and 404. Returns The reserved route produced from ReservedRouteFormat . Remarks The returned path is for framework middleware, direct preview, and tooling such as static export. It should not be exposed as an application-owned route. Type CorsOptions Represents configuration options for Cross-Origin Resource Sharing (CORS) policies. Property EnableAllOriginsInDevelopment bool EnableAllOriginsInDevelopment { get; set; } Gets or sets a value indicating whether all origins are allowed when running in the development environment. Defaults to true . Property EnableCors bool EnableCors { get; set; } Gets or sets a value indicating whether CORS is enabled for the application. Defaults to false . Property AllowedOrigins string[] AllowedOrigins { get; set; } Gets or sets the collection of origins permitted to make cross-origin requests. Defaults to an empty array. Property PolicyName string PolicyName { get; set; } Gets or sets the name of the CORS policy to register. Defaults to \u0022DefaultCorsPolicy\u0022 . Property Default CorsOptions Default { get; } Gets a default instance of CorsOptions with default configuration settings. Type AppSurfaceWebDevelopmentPortDefaults Resolves a deterministic development port for AppSurface web hosts in development when the caller has not already supplied explicit ASP.NET Core endpoint configuration. Method Resolve AppSurfaceWebDevelopmentPortResolution Resolve ( string[] args , string currentDirectory , string applicationBaseDirectory , Func\u003Cstring, string?\u003E environmentReader , IEnumerable\u003Cstring\u003E? environmentVariableNames = null ) Applies a deterministic localhost --urls fallback in development when command-line arguments, environment variables, and local appsettings files do not specify where the host should listen. Parameters args The command-line arguments supplied by the caller. currentDirectory The current working directory for the process. applicationBaseDirectory The application base directory for the host entry assembly. environmentReader Reads environment variables needed to detect the environment and explicit endpoint configuration. environmentVariableNames The available environment variable names, used to detect named Kestrel endpoint variables. Returns A resolution describing the effective arguments. If no fallback was needed, the returned arguments match the supplied args . Type AppSurfaceWebDevelopmentPortResolution Describes the effective command-line arguments after AppSurface web development defaults have been resolved. Parameters Args The effective arguments that should be passed into host startup. AppliedPort The fallback port applied by the resolver, if any. SeedPath The normalized workspace or project path used to compute the fallback port. Type StaticFilesOptions Represents configuration options for serving static files and web assets. Property Default StaticFilesOptions Default { get; } Gets a default instance of StaticFilesOptions with default configuration settings. Property EnableStaticFiles bool EnableStaticFiles { get; set; } Gets or sets a value indicating whether static files are enabled. This is automatically enabled when MvcSupport.ControllersWithViews or higher is used. Property EnableStaticWebAssets bool EnableStaticWebAssets { get; set; } Gets or sets a value indicating whether static web assets (from RCLs) are enabled. This is automatically enabled in the development environment. Type BrowserStatusPageDescriptor Describes one built-in browser status page that AppSurface can preview, re-execute, and render. Parameters StatusCode The supported HTTP status code for this descriptor. AppViewPath The conventional status-specific app or shared-library override view path. ReservedRoute The framework-owned preview and re-execute route for this status code. Title The document title used by the framework fallback view. Eyebrow The short label rendered above the fallback heading. Heading The main fallback heading shown to browser users. Description The fallback explanation of what happened and how to recover. PrimaryActionText The fallback primary recovery action label. Remarks Descriptors are internal framework metadata for the current built-in status set: 401, 403, and 404. Use TryGet(int, out BrowserStatusPageDescriptor) before routing or rendering arbitrary status codes; unsupported codes should not be re-executed through the browser status page pipeline. Method TryGet bool TryGet ( int statusCode , out BrowserStatusPageDescriptor? descriptor ) Attempts to resolve a built-in browser status page descriptor for an HTTP status code. Parameters statusCode The HTTP status code to resolve. descriptor When this method returns true , the descriptor for statusCode ; otherwise null . Returns true for supported status codes 401, 403, and 404; otherwise false . Remarks Unknown status codes are intentionally rejected so production exception pages and future status families can be designed separately instead of accidentally using the 401/403/404 browser-page contract. Property FrameworkFallbackViewPath string FrameworkFallbackViewPath { get; } Gets the shared framework fallback view path used when AppViewPath cannot be resolved. Remarks The fallback is shared across all supported statuses. App and shared Razor Class Library overrides remain status-specific through AppViewPath . Property Supported IReadOnlyList\u003CBrowserStatusPageDescriptor\u003E Supported { get; } Gets all built-in browser status page descriptors in the order AppSurface validates them. Remarks This list is the built-in set for the current release, not a promise that every browser-relevant status is supported. Callers should use TryGet(int, out BrowserStatusPageDescriptor) for lookup instead of assuming a status code is present. Type BrowserStatusPageModel Represents the model passed to AppSurface\u0027s conventional browser status page view. Parameters StatusCode The HTTP status code being rendered. AppSurface currently produces 401, 403, or 404. OriginalPath The nullable original request path that produced the status response, when middleware can provide it. OriginalQueryString The nullable original request query string that produced the status response, when middleware can provide it. Remarks The framework renderer normalizes missing or malformed route status values to 404 before creating the default model, but explicit status values must be supported by the built-in browser status page descriptors. Custom producers should pass only status codes their view understands. OriginalPath and OriginalQueryString are null for direct preview requests and can also be absent when upstream middleware strips or replaces status-code re-execution metadata. Status-page views should prefer this model for user-facing recovery copy because it captures the original failed request after AppSurface re-executes the framework route. Read HttpContext.Request only for current-request concerns such as URL generation; during re-execution it points at the reserved framework route. Treat the query string as display-only metadata, not as authorization or security input, and do not assume the path has a trailing slash or app-specific normalization. Type ExceptionPageModel Represents the model passed to AppSurface\u0027s conventional production exception view. Parameters StatusCode The HTTP status code being rendered. RequestId The request identifier that app logs can use to correlate the failure. Remarks This model intentionally excludes exception details, request headers, cookies, route values, and form fields. Production error pages should help users recover and help operators correlate logs without disclosing request internals or implementation details. Type WebStartup\u003CTModule\u003E Provides a base implementation for a web-based AppSurfaceStartup{TModule} that handles MVC, CORS, and static file configuration based on registered IAppSurfaceWebModule instances. Type Parameters TModule The root IAppSurfaceWebModule for the application. Method WithOptions WebStartup\u003CTModule\u003E WithOptions ( Action\u003CWebOptions\u003E? configureOptions = null ) Registers an optional callback to customize WebOptions and enables fluent chaining. Parameters configureOptions An optional action invoked later when WebOptions are built to modify configuration. Returns The same WebStartup{TModule} instance to support fluent configuration. Method RunAsync Task RunAsync ( string[] args ) Starts the web host with AppSurface Web\u0027s deterministic development-port fallback when the caller has not explicitly configured an endpoint through command-line arguments, environment variables, or appsettings. Parameters args The command-line arguments supplied by the caller. Returns A task that completes when the web host run exits. Method ResolveDevelopmentPortDefaults AppSurfaceWebDevelopmentPortResolution ResolveDevelopmentPortDefaults ( string[] args ) Resolves the effective command-line arguments before the web host starts. Parameters args The command-line arguments supplied by the caller. Returns The resolved startup arguments and any deterministic development-port metadata. Method RunResolvedAsync Task RunResolvedAsync ( string[] args ) Runs the base host startup path with arguments after AppSurface Web development defaults have been resolved. Parameters args The effective command-line arguments to pass into the host. Returns A task that completes when the web host run exits. Method BuildModules void BuildModules ( StartupContext context ) Collects and caches all IAppSurfaceWebModule instances found in the provided startup context. This method is idempotent. Parameters context The startup context whose dependencies and root module are inspected for web modules. Remarks This method is idempotent; subsequent calls have no effect once modules are built. Method BuildWebOptions void BuildWebOptions ( StartupContext context ) Initializes and caches WebOptions by applying configuration from discovered modules and the optional custom callback; enables static file support when MVC is configured for controllers with views. Parameters context The startup context used when invoking module and custom option configuration. Remarks This method is idempotent; subsequent calls have no effect once options are built. Method ConfigureServicesForAppType void ConfigureServicesForAppType ( StartupContext context , IServiceCollection services ) Configures services required for the web application: registers MVC application parts from the entry assembly and enabled web modules, and adds a CORS policy when CORS is enabled. Parameters context Startup context providing environment information and the entry-point assembly. services The service collection to register MVC and CORS services into. Exceptions InvalidOperationException Thrown when CORS is enabled but no allowed origins are specified, except when all origins are explicitly allowed in development. Method ConfigureBuilderForAppType IHostBuilder ConfigureBuilderForAppType ( StartupContext context , IHostBuilder builder ) Configures the provided host builder with web host defaults and registers the application\u0027s web initialization pipeline. Parameters context The startup context used to collect modules and build web options. builder The host builder to configure. Returns The same IHostBuilder configured with web host defaults and the application\u0027s initialization pipeline. Method InitializeWebApplication void InitializeWebApplication ( StartupContext context , IApplicationBuilder app ) Configures the application\u0027s middleware pipeline and endpoint routing for the web application. Parameters context The startup context containing environment, entry point, and discovered modules used during configuration. app The application builder to configure (middleware, routing, CORS, endpoints, etc.). Type BrowserStatusPageRenderer Resolves and renders AppSurface\u0027s conventional browser status page views. Remarks View resolution prefers the status-specific app/shared Razor Class Library path first, for example ~/Views/Shared/403.cshtml . If that view is missing, the renderer falls back to AppSurface\u0027s shared framework view. Resolved paths are cached per status code so a 401 override cannot accidentally satisfy a later 403 or 404 render. Method ValidateConfiguredViews void ValidateConfiguredViews () Performs eager validation of all configured conventional browser status page views. Remarks Call this during startup to fail fast if neither the conventional app/shared view nor the framework fallback view can be resolved for any supported status. Runtime rendering also resolves lazily, but this method turns a missing view into a predictable startup error instead of a request-time failure. Validation also warms and pins the runtime view-path cache by resolving every BrowserStatusPageDescriptor.Supported entry. If an app adds or removes status page views after this method runs, the startup-selected app or framework fallback path remains in use for the process lifetime. Method RenderAsync Task RenderAsync ( HttpContext httpContext ) Renders the resolved conventional browser status page view into the current HTTP response. Parameters httpContext The current request context used to build the model and execute the Razor view. Remarks The rendered model is always a BrowserStatusPageModel . Its status defaults to 404 when the request is a direct render without a re-execute feature or reserved-route status code. This method does not change HttpResponse.StatusCode itself, which lets direct previews keep their existing 200 response and re-executed status requests preserve their original HTTP status. CreateModel(HttpContext) can receive an explicit status from re-execution metadata or the reserved route. That status must be supported by BrowserStatusPageDescriptor ; otherwise this method throws instead of rendering a mismatched page for the existing HttpResponse.StatusCode . Type MvcOptions Represents configuration options for ASP.NET Core MVC services and features. Property Default MvcOptions Default { get; } Gets a new default instance of MvcOptions configured with MvcSupport.Controllers . Property MvcSupportLevel MvcSupport MvcSupportLevel { get; init; } Gets the level of MVC support to register (e.g., Controllers only, or Controllers with Views). Property ConfigureMvc Action\u003CIMvcBuilder\u003E? ConfigureMvc { get; init; } Gets an optional delegate for performing advanced configuration of the IMvcBuilder . Enum MvcSupport Specifies the level of MVC feature support to enable in the web application. Remarks The numeric values are explicit because this public enum may be persisted, serialized, or bound by applications. New values should be appended without changing the values documented here. Type IAppSurfaceWebModule Defines a module that exposes web-specific configuration, endpoints, and middleware. Method ConfigureWebOptions void ConfigureWebOptions ( StartupContext context , WebOptions options ) Configures WebOptions for the application, such as MVC, CORS, and static files. Parameters context The startup context for the application. options The options to be configured. Method ConfigureEndpoints void ConfigureEndpoints ( StartupContext context , IEndpointRouteBuilder endpoints ) Allows the module to configure endpoint routes for the application. Parameters context Startup context providing environment and configuration for the module. endpoints Endpoint route builder used to map endpoints (routes, hubs, etc.). Method ConfigureWebApplication void ConfigureWebApplication ( StartupContext context , IApplicationBuilder app ) Configure the ASP.NET Core request pipeline for this module. Parameters context Startup information and services available to the module during application initialization. app The application\u0027s request pipeline builder used to register middleware, routing, and other pipeline components. Property IncludeAsApplicationPart bool IncludeAsApplicationPart { get; } Gets a value indicating whether this module\u0027s assembly should be searched for MVC application parts (controllers, views, etc.). Defaults to false.","snippet":"Namespaces OpenApi Scalar Tailwind Type WebOptions Represents configuration options for the web application, including MVC, CORS, and static file settings. Property Mvc MvcOptions Mvc { get; set; } Gets or sets...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-AppSurfaceWebDevelopmentPortDefaults","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-AppSurfaceWebDevelopmentPortDefaults","title":"AppSurfaceWebDevelopmentPortDefaults","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","AppSurfaceWebDevelopmentPortDefaults"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-AppSurfaceWebDevelopmentPortDefaults"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-AppSurfaceWebDevelopmentPortResolution","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-AppSurfaceWebDevelopmentPortResolution","title":"AppSurfaceWebDevelopmentPortResolution","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","AppSurfaceWebDevelopmentPortResolution"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-AppSurfaceWebDevelopmentPortResolution"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageDefaults","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageDefaults","title":"BrowserStatusPageDefaults","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","BrowserStatusPageDefaults"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-BrowserStatusPageDefaults"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageDescriptor","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageDescriptor","title":"BrowserStatusPageDescriptor","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","BrowserStatusPageDescriptor"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-BrowserStatusPageDescriptor"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageMode","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageMode","title":"BrowserStatusPageMode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","BrowserStatusPageMode"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-BrowserStatusPageMode"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageModel","title":"BrowserStatusPageModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","BrowserStatusPageModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-BrowserStatusPageModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageRenderer","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-BrowserStatusPageRenderer","title":"BrowserStatusPageRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","BrowserStatusPageRenderer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-BrowserStatusPageRenderer"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ConventionalExceptionPageDefaults","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ConventionalExceptionPageDefaults","title":"ConventionalExceptionPageDefaults","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","ConventionalExceptionPageDefaults"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-ConventionalExceptionPageDefaults"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ConventionalExceptionPageRenderer","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ConventionalExceptionPageRenderer","title":"ConventionalExceptionPageRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","ConventionalExceptionPageRenderer"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-ConventionalExceptionPageRenderer"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-CorsOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-CorsOptions","title":"CorsOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","CorsOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-CorsOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ErrorPagesOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ErrorPagesOptions","title":"ErrorPagesOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","ErrorPagesOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-ErrorPagesOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ExceptionPageModel","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-ExceptionPageModel","title":"ExceptionPageModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","ExceptionPageModel"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-ExceptionPageModel"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-IAppSurfaceWebModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-IAppSurfaceWebModule","title":"IAppSurfaceWebModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","IAppSurfaceWebModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-IAppSurfaceWebModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-MvcOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-MvcOptions","title":"MvcOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","MvcOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-MvcOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-MvcSupport","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-MvcSupport","title":"MvcSupport","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","MvcSupport"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-MvcSupport"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-StaticFilesOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-StaticFilesOptions","title":"StaticFilesOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","StaticFilesOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-StaticFilesOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebApp-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebApp-1","title":"WebApp\u003CTModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","WebApp\u003CTModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-WebApp-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebApp-2","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebApp-2","title":"WebApp\u003CTStartup, TModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","WebApp\u003CTStartup, TModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-WebApp-2"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebOptions","title":"WebOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","WebOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-WebOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebStartup-1","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.html#ForgeTrust-AppSurface-Web-WebStartup-1","title":"WebStartup\u003CTModule\u003E","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Web","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","WebStartup\u003CTModule\u003E"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web#ForgeTrust-AppSurface-Web-WebStartup-1"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.OpenApi.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.OpenApi.html","title":"OpenApi","summary":"Type AppSurfaceWebOpenApiModule A web module that integrates OpenAPI/Swagger document generation into the application. Remarks Use AppSurfaceWebOpenApiModule when AppSurface should own the default OpenAPI service and...","headings":["AppSurfaceWebOpenApiModule","ConfigureServices","ConfigureEndpoints","RegisterDependentModules","ConfigureHostBeforeServices","ConfigureHostAfterServices","ConfigureWebApplication"],"bodyText":"Type AppSurfaceWebOpenApiModule A web module that integrates OpenAPI/Swagger document generation into the application. Remarks Use AppSurfaceWebOpenApiModule when AppSurface should own the default OpenAPI service and endpoint wiring for an app. The module registers ASP.NET Core OpenAPI generation, endpoint API exploration, document and operation transformers, and maps the OpenAPI endpoint during endpoint configuration. The default document title is {ApplicationName} | v1 , and the built-in transformers remove the framework implementation tag ForgeTrust.AppSurface.Web while preserving other tags. Register a custom module or add additional OpenAPI options when an application needs multiple documents, custom versioning, authentication metadata, or different tag policies. Pitfall: transformer tag collections may be null and this module must run before consumers expect the MapOpenApi endpoint to be mapped. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Configures services needed for OpenAPI, including document and operation transformers to customize the generated schema. Parameters context The startup context that supplies the application name used in the generated document title. services The service collection receiving OpenAPI and endpoint exploration registrations. Remarks ConfigureServices reads StartupContext.ApplicationName for the default document title, registers singleton-safe transformer delegates through ASP.NET Core OpenAPI options, and adds endpoint API exploration. Call this through normal AppSurface module startup rather than invoking it after the host service provider has been built. Method ConfigureEndpoints void ConfigureEndpoints ( StartupContext context , IEndpointRouteBuilder endpoints ) Maps the OpenAPI document endpoint. Parameters context The startup context. endpoints The endpoint route builder. Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers dependencies for this module; currently no implementation is required. Parameters builder The module dependency builder. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , IHostBuilder builder ) Executes pre-service host configuration; currently no implementation is required. Parameters context The startup context. builder The host builder. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , IHostBuilder builder ) Executes post-service host configuration; currently no implementation is required. Parameters context The startup context. builder The host builder. Method ConfigureWebApplication void ConfigureWebApplication ( StartupContext context , IApplicationBuilder app ) Configures the web application pipeline; currently no implementation is required. Parameters context The startup context. app The application builder.","snippet":"Type AppSurfaceWebOpenApiModule A web module that integrates OpenAPI/Swagger document generation into the application. Remarks Use AppSurfaceWebOpenApiModule when AppSurface should own the default OpenAPI service and...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"OpenApi","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","OpenApi"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.OpenApi"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.OpenApi.html#ForgeTrust-AppSurface-Web-OpenApi-AppSurfaceWebOpenApiModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.OpenApi.html#ForgeTrust-AppSurface-Web-OpenApi-AppSurfaceWebOpenApiModule","title":"AppSurfaceWebOpenApiModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"OpenApi","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","OpenApi","AppSurfaceWebOpenApiModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.OpenApi#ForgeTrust-AppSurface-Web-OpenApi-AppSurfaceWebOpenApiModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Scalar.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Scalar.html","title":"Scalar","summary":"Type AppSurfaceWebScalarModule A web module that integrates Scalar API reference documentation into the application. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection...","headings":["AppSurfaceWebScalarModule","ConfigureServices","RegisterDependentModules","ConfigureEndpoints","ConfigureHostBeforeServices","ConfigureHostAfterServices","ConfigureWebApplication"],"bodyText":"Type AppSurfaceWebScalarModule A web module that integrates Scalar API reference documentation into the application. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Configures services needed for Scalar; currently no implementation is required. Parameters context The startup context. services The service collection. Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers dependencies for this module, specifically AppSurfaceWebOpenApiModule . Parameters builder The module dependency builder. Method ConfigureEndpoints void ConfigureEndpoints ( StartupContext context , IEndpointRouteBuilder endpoints ) Maps the Scalar API reference endpoint. Parameters context The startup context. endpoints The endpoint route builder. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , IHostBuilder builder ) Executes pre-service host configuration; currently no implementation is required. Parameters context The startup context. builder The host builder. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , IHostBuilder builder ) Executes post-service host configuration; currently no implementation is required. Parameters context The startup context. builder The host builder. Method ConfigureWebApplication void ConfigureWebApplication ( StartupContext context , IApplicationBuilder app ) Configures the web application pipeline; currently no implementation is required. Parameters context The startup context. app The application builder.","snippet":"Type AppSurfaceWebScalarModule A web module that integrates Scalar API reference documentation into the application. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Scalar","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Scalar"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Scalar"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Scalar.html#ForgeTrust-AppSurface-Web-Scalar-AppSurfaceWebScalarModule","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Scalar.html#ForgeTrust-AppSurface-Web-Scalar-AppSurfaceWebScalarModule","title":"AppSurfaceWebScalarModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Scalar","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Scalar","AppSurfaceWebScalarModule"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Scalar#ForgeTrust-AppSurface-Web-Scalar-AppSurfaceWebScalarModule"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html","title":"Tailwind","summary":"Type TailwindExtensions Provides extension methods for registering Tailwind CSS services. Method AddTailwind 2 overloads IServiceCollection AddTailwind ( this IServiceCollection services ) Adds Tailwind CSS services...","headings":["TailwindExtensions","AddTailwind","TailwindCliManager","GetTailwindPath","BuildInvocation","GetCurrentRid","ResolveRid","BaseDirectoryOverride","AssemblyDirectoryOverride","RidOverride","IsOSPlatformOverride","ProcessArchitectureOverride","TailwindCliInvocation","TailwindWatchService","ExecuteTailwindProcessAsync","GetPathComparison","HostPathsAreCaseInsensitive","TailwindOptions","Enabled","InputPath","OutputPath"],"bodyText":"Type TailwindExtensions Provides extension methods for registering Tailwind CSS services. Method AddTailwind 2 overloads IServiceCollection AddTailwind ( this IServiceCollection services ) Adds Tailwind CSS services to the service collection. Parameters services The service collection. Returns The service collection for chaining. Remarks Use this overload when the default TailwindOptions are sufficient. It delegates to AddTailwind(IServiceCollection, Action{TailwindOptions}) and registers both TailwindCliManager and the hosted TailwindWatchService . In tests or non-hosted scenarios, remember that the hosted watch service can start background file/process work. IServiceCollection AddTailwind ( this IServiceCollection services , Action\u003CTailwindOptions\u003E configureOptions ) Adds Tailwind CSS services with custom configuration to the service collection. Parameters services The service collection. configureOptions An action to configure the TailwindOptions . Returns The service collection for chaining. Remarks Use this overload to customize TailwindOptions before AppSurface registers TailwindCliManager and TailwindWatchService . The watch service is registered as an IHostedService , so hosts that should not run Tailwind background work should avoid this extension or replace the hosted service registration intentionally. Type TailwindCliManager Manages the location and execution of the Tailwind CLI binary. Method GetTailwindPath string GetTailwindPath () Gets the path to the Tailwind CLI binary. Returns The absolute path to the tailwindcss executable. Exceptions FileNotFoundException Thrown if the binary cannot be found in runtimes, local directory, or PATH. Remarks Resolution proceeds in this order: RID-specific runtime assets under AppContext.BaseDirectory . A flat binary next to the application under AppContext.BaseDirectory . RID-specific runtime assets relative to this assembly, including local development runtime build outputs when running inside this repository. The system PATH as an escape hatch for custom or Node-managed Tailwind setups, including Windows shell shims such as .cmd and .ps1 . If none of these locations contain a compatible binary, the method throws FileNotFoundException . Method BuildInvocation TailwindCliInvocation BuildInvocation ( string tailwindPath , IReadOnlyList\u003Cstring\u003E tailwindArgs ) Builds the process invocation needed to execute a resolved Tailwind CLI path. Parameters tailwindPath The resolved Tailwind CLI path returned by GetTailwindPath . tailwindArgs The Tailwind CLI arguments to forward to the process. Returns A TailwindCliInvocation describing the executable to launch and the full ordered argument list. Remarks Windows PATH resolution can return Node-managed shell shims such as .cmd or .ps1 . These files cannot be launched reliably with System.Diagnostics.ProcessStartInfo.UseShellExecute disabled, so they are wrapped with cmd.exe or powershell.exe as appropriate. Method GetCurrentRid string GetCurrentRid () Gets the Runtime Identifier (RID) for the current platform. Returns The RID string (e.g., \u0022win-x64\u0022, \u0022linux-arm64\u0022). Remarks Must be kept in sync with the RID logic in the runtime package projects and build/ForgeTrust.AppSurface.Web.Tailwind.targets. Unsupported operating systems or architectures return \u0022unknown\u0022 . Windows Arm64 intentionally maps to win-x64 because Tailwind v4.1.18 does not ship a native Windows Arm64 standalone binary. Method ResolveRid string ResolveRid ( OSPlatform osPlatform , Architecture architecture ) Resolves the Tailwind runtime identifier for a specific platform and process architecture. Parameters osPlatform The operating system platform to evaluate. architecture The process architecture to map. Returns The Tailwind runtime identifier for the supplied platform/architecture pair. Remarks Must be kept in sync with the RID logic in the runtime package projects and build/ForgeTrust.AppSurface.Web.Tailwind.targets. Property BaseDirectoryOverride string? BaseDirectoryOverride { get; set; } Gets or sets a directory to override AppContext.BaseDirectory for testing. Property AssemblyDirectoryOverride string? AssemblyDirectoryOverride { get; set; } Gets or sets a directory to override the resolved assembly directory for testing isolated fallback lookup. Property RidOverride string? RidOverride { get; set; } Gets or sets a runtime identifier override for tests that need to exercise non-host RID resolution paths. Property IsOSPlatformOverride Func\u003COSPlatform, bool\u003E? IsOSPlatformOverride { get; set; } Gets or sets an operating-system detector override for tests that need deterministic platform simulation. Property ProcessArchitectureOverride Func\u003CArchitecture\u003E? ProcessArchitectureOverride { get; set; } Gets or sets a process-architecture override for tests that need deterministic RID resolution. Type TailwindCliInvocation Represents the concrete process invocation required to launch the resolved Tailwind CLI. Parameters FileName The executable or launcher to start. Arguments The complete ordered argument list to pass to FileName . Type TailwindWatchService A background service that runs the Tailwind CLI in watch mode during development. Method ExecuteTailwindProcessAsync Task\u003CCommandResult\u003E ExecuteTailwindProcessAsync ( string fileName , IReadOnlyList\u003Cstring\u003E args , string workingDirectory , CancellationToken cancellationToken ) Executes the Tailwind CLI process. Parameters fileName The path to the executable. args The arguments. workingDirectory The working directory. cancellationToken The cancellation token. Returns The command result returned by the Tailwind CLI process. Remarks Internal virtual to allow mocking in unit tests. Method GetPathComparison StringComparison GetPathComparison () Resolves the path-comparison behavior used when validating Tailwind input/output paths. Returns The string-comparison behavior used when evaluating Tailwind input and output paths. Remarks The default implementation only assumes case-insensitive paths on Windows so development hosts on case-sensitive volumes are not rejected by a false positive same-file check. Override HostPathsAreCaseInsensitive in tests or specialized hosts that know they should compare paths case-insensitively on another platform. Method HostPathsAreCaseInsensitive bool HostPathsAreCaseInsensitive () Determines whether the current host should treat filesystem paths as case-insensitive for Tailwind path validation. Returns true when the host should conservatively compare input and output paths case-insensitively; otherwise false . Remarks The default behavior treats only Windows as case-insensitive. Hosts that run on a known case-insensitive non-Windows volume can override this method to opt into StringComparison.OrdinalIgnoreCase . Type TailwindOptions Configuration options for the Tailwind CSS integration. Remarks Use these options with services.AddTailwind(...) to control both build-time compilation and development watch behavior. Defaults: Enabled defaults to true . InputPath defaults to wwwroot/css/app.css . OutputPath defaults to wwwroot/css/site.gen.css . Paths are resolved relative to the app content root. Common misconfigurations include pointing at a missing input file, using whitespace-only paths, or choosing an output path whose parent directory is not writable. Property Enabled bool Enabled { get; set; } Gets or sets a value indicating whether Tailwind CSS integration is enabled. Remarks Leave this enabled for normal development and build pipelines. Set it to false only when a host intentionally opts out of Tailwind compilation or provides CSS through another mechanism. Property InputPath string InputPath { get; set; } Gets or sets the path to the input CSS file. Remarks Defaults to wwwroot/css/app.css . The value should be a non-empty relative path to a readable .css file under the application content root. Property OutputPath string OutputPath { get; set; } Gets or sets the path to the output CSS file. Remarks Defaults to wwwroot/css/site.gen.css . The value should be a non-empty relative path whose parent directory exists and is writable. Keep the output under wwwroot/ when the generated stylesheet needs to participate in ASP.NET Core static web asset discovery for build and publish output. Avoid pointing this at the same file as InputPath .","snippet":"Type TailwindExtensions Provides extension methods for registering Tailwind CSS services. Method AddTailwind 2 overloads IServiceCollection AddTailwind ( this IServiceCollection services ) Adds Tailwind CSS services...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Tailwind","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Tailwind"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindCliManager","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindCliManager","title":"TailwindCliManager","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Tailwind","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Tailwind","TailwindCliManager"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind#ForgeTrust-AppSurface-Web-Tailwind-TailwindCliManager"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindCliManager-TailwindCliInvocation","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindCliManager-TailwindCliInvocation","title":"TailwindCliInvocation","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Tailwind","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Tailwind","TailwindCliInvocation"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind#ForgeTrust-AppSurface-Web-Tailwind-TailwindCliManager-TailwindCliInvocation"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindExtensions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindExtensions","title":"TailwindExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Tailwind","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Tailwind","TailwindExtensions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind#ForgeTrust-AppSurface-Web-Tailwind-TailwindExtensions"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindOptions","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindOptions","title":"TailwindOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Tailwind","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Tailwind","TailwindOptions"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind#ForgeTrust-AppSurface-Web-Tailwind-TailwindOptions"},{"id":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindWatchService","path":"/docs/Namespaces/ForgeTrust.AppSurface.Web.Tailwind.html#ForgeTrust-AppSurface-Web-Tailwind-TailwindWatchService","title":"TailwindWatchService","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Tailwind","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","AppSurface","Web","Tailwind","TailwindWatchService"],"sourcePath":"Namespaces/ForgeTrust.AppSurface.Web.Tailwind#ForgeTrust-AppSurface-Web-Tailwind-TailwindWatchService"},{"id":"Namespaces/ForgeTrust.html","path":"/docs/Namespaces/ForgeTrust.html","title":"ForgeTrust","summary":"Namespaces AppSurface RazorWire","headings":[],"bodyText":"Namespaces AppSurface RazorWire","snippet":"Namespaces AppSurface RazorWire","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"ForgeTrust","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust"],"sourcePath":"Namespaces/ForgeTrust"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html","title":"Bridge","summary":"Type ViewComponentStreamHelper Internal helper for rendering view components into Turbo Stream fragments. Method RenderComponentStreamAsync Task\u003Cstring\u003E RenderComponentStreamAsync ( ViewContext viewContext , string...","headings":["ViewComponentStreamHelper","RenderComponentStreamAsync","ViewComponentStreamAction","RenderAsync","ViewComponentByNameStreamAction","RazorPartialRenderer","RenderPartialToStringAsync","IRazorPartialRenderer","RazorWireStreamResult","ExecuteResultAsync","CreateViewContext","RawHtmlStreamAction","NullView","PartialViewStreamAction","RazorWireBridge","Frame","FrameComponent","CreateStream","TurboFrameViewModel","Id","PartialView","ViewComponent","Model","IRazorWireStreamAction"],"bodyText":"Type ViewComponentStreamHelper Internal helper for rendering view components into Turbo Stream fragments. Method RenderComponentStreamAsync Task\u003Cstring\u003E RenderComponentStreamAsync ( ViewContext viewContext , string action , string target , dynamic componentIdentifier , object? arguments ) Renders a view component into a Turbo Stream XML fragment. Parameters viewContext The current Razor view context used as the basis for rendering. action The Turbo Stream action (e.g., \u0022replace\u0022, \u0022append\u0022). target The DOM element identifier to update. componentIdentifier The view component to invoke; either a CLR Type or the component\u0027s string name. arguments Optional arguments to pass to the view component. Returns A Turbo Stream XML fragment whose \u0060action\u0060 and \u0060target\u0060 attributes are HTML-encoded and whose \u003Ctemplate\u003E contains the rendered component HTML. Type ViewComponentStreamAction A Turbo Stream action that renders a view component by its Type . Method RenderAsync Task\u003Cstring\u003E RenderAsync ( ViewContext viewContext , CancellationToken cancellationToken = default ) Renders the configured view component into a Turbo Stream fragment. Parameters viewContext The current MVC view context used to execute and render the view component. cancellationToken A token to observe while deciding whether to proceed. Returns A string containing a \u003Cturbo-stream\u003E element whose action and target attributes are HTML-encoded and whose \u003Ctemplate\u003E contains the component\u0027s rendered HTML. Type ViewComponentByNameStreamAction A Turbo Stream action that renders a view component by its name. Method RenderAsync Task\u003Cstring\u003E RenderAsync ( ViewContext viewContext , CancellationToken cancellationToken = default ) Render the configured view component (by name) into a Turbo Stream fragment. Parameters viewContext The current Razor view context used to execute and render the view component. cancellationToken A token to observe while waiting for the task to complete. Returns A string containing a \u003Cturbo-stream\u003E element whose action and target attributes are HTML-encoded and whose \u003Ctemplate\u003E contains the rendered component HTML. Type RazorPartialRenderer Implements IRazorPartialRenderer using the Razor view engine. Method RenderPartialToStringAsync Task\u003Cstring\u003E RenderPartialToStringAsync ( string viewName , object? model = null , CancellationToken cancellationToken = default ) Remarks Because this method executes outside of an HTTP request context, it uses a blank ActionContext (with empty RouteData and ActionDescriptor ). As a result, the IRazorViewEngine may not be able to locate views that are scoped to a specific controller (e.g., Views/ControllerName/ViewName.cshtml ) unless the full path is provided (e.g., ~/Views/Reactivity/_MyPartial.cshtml ). Shared views (e.g., Views/Shared/_MyPartial.cshtml ) are generally resolvable by name. Type IRazorPartialRenderer Provides a mechanism to render Razor partial views to strings, specifically useful for background services and non-HTTP request contexts. Method RenderPartialToStringAsync Task\u003Cstring\u003E RenderPartialToStringAsync ( string viewName , object? model = null , CancellationToken cancellationToken = default ) Renders a partial view as an HTML string. Parameters viewName The name or path of the partial view to render. model Optional model to pass to the view. cancellationToken A token to monitor for cancellation requests. Returns A task that represents the asynchronous render operation. The task result contains the rendered HTML string. Type RazorWireStreamResult An IActionResult that renders and streams Turbo Stream actions to the response. Method ExecuteResultAsync Task ExecuteResultAsync ( ActionContext context ) Streams rendered Turbo Stream HTML for the configured actions to the HTTP response. Parameters context The current action context used to build the view context and access the HTTP response. Remarks Generates and stores antiforgery tokens before sending any response data, sets the response Content-Type to \u0022text/vnd.turbo-stream.html\u0022, and streams each action\u0027s rendered HTML to the response using UTF-8 encoding. Rendering of actions is performed asynchronously in parallel. Method CreateViewContext ViewContext CreateViewContext ( ActionContext actionContext ) Creates a ViewContext configured for rendering the stream actions, optionally inheriting ViewData and TempData from the associated controller. Parameters actionContext The current ActionContext used to build the ViewContext. Returns A ViewContext configured with a NullView , the prepared ViewData, TempData (the controller\u0027s if available or obtained from ITempDataDictionaryFactory), TextWriter.Null, and default HtmlHelperOptions. Type RawHtmlStreamAction Method RenderAsync Task\u003Cstring\u003E RenderAsync ( ViewContext viewContext , CancellationToken cancellationToken = default ) Produces the stored raw HTML as the rendered output for the given view context. Parameters viewContext The view rendering context supplied to the action. cancellationToken Cancellation token (ignored for raw HTML). Returns The stored HTML string. Type NullView Method RenderAsync Task RenderAsync ( ViewContext viewContext ) Performs no rendering and completes immediately. Parameters viewContext The rendering context provided by the framework; this implementation ignores it. Returns A completed Task representing the finished render operation. Type PartialViewStreamAction A Turbo Stream action that renders a partial view as its content. Method RenderAsync Task\u003Cstring\u003E RenderAsync ( ViewContext viewContext , CancellationToken cancellationToken = default ) Renders the configured partial view and wraps its output in a Turbo Stream element. Parameters viewContext The current view context used to locate services and render the partial view. cancellationToken A token to observe while waiting for the task to complete. Returns The turbo-stream HTML string containing the rendered partial inside a \u003Ctemplate\u003E element. Exceptions InvalidOperationException Thrown if the partial view cannot be located. Type RazorWireBridge Provides static methods for creating Turbo Frame results and RazorWire stream builders. Method Frame PartialViewResult Frame ( Controller controller , string id , string partialView , object? model = null ) Creates a partial result that renders a turbo frame containing the specified inner partial view and model. Parameters controller The controller used to produce the partial view result. id The identifier to assign to the turbo frame. partialView The name of the inner partial view to render inside the frame. model An optional model to pass to the inner partial view. Returns A PartialViewResult that renders the RazorWire/_TurboFrame partial populated with the specified id, partial view, and model. Remarks Also exposes the frame identifier by setting controller.ViewData[\u0022TurboFrameId\u0022] . Method FrameComponent PartialViewResult FrameComponent ( Controller controller , string id , string componentName , object? model = null ) Creates a partial result that renders a Turbo Frame containing the specified view component. The frame identifier is exposed via Controller.ViewData[\u0022TurboFrameId\u0022] . Parameters controller The controller instance from which to produce results. id Identifier for the turbo frame. componentName Name of the view component to render inside the frame. model Optional model to pass to the view component. Returns A PartialViewResult that renders the RazorWire/_TurboFrame partial with a TurboFrameViewModel . Method CreateStream RazorWireStreamBuilder CreateStream () Creates a new RazorWireStreamBuilder for fluidly configuring and producing Turbo Stream actions. Returns A new RazorWireStreamBuilder instance ready to configure stream updates. Method CreateViewContext Microsoft.AspNetCore.Mvc.Rendering.ViewContext CreateViewContext ( this Controller controller ) Creates a Microsoft.AspNetCore.Mvc.Rendering.ViewContext configured to render outside of a regular view using the controller\u0027s context and data. Parameters controller The controller whose context and data are used as the basis for the new Microsoft.AspNetCore.Mvc.Rendering.ViewContext . Returns A Microsoft.AspNetCore.Mvc.Rendering.ViewContext configured with the controller\u0027s data and a no-op view. Type NullView Method RenderAsync Task RenderAsync ( Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext ) A no-op view that does not render any content. Parameters viewContext The view context provided for rendering; this implementation ignores it. Returns A completed Task . Type TurboFrameViewModel Data model used for rendering the Turbo Frame partial view. Property Id string Id { get; set; } Gets or sets the unique identifier for the Turbo Frame. Property PartialView string? PartialView { get; set; } Gets or sets the name of the partial view to render inside the frame, if any. Property ViewComponent string? ViewComponent { get; set; } Gets or sets the name of the view component to render inside the frame, if any. Property Model object? Model { get; set; } Gets or sets the optional model to pass to the partial view or view component. Type IRazorWireStreamAction Represents an action to be performed in a RazorWire stream (e.g., append, replace). Method RenderAsync Task\u003Cstring\u003E RenderAsync ( ViewContext viewContext , CancellationToken cancellationToken = default ) Renders the stream action to an HTML string using the provided view rendering context. Parameters viewContext The Razor view rendering context used to produce the HTML output. cancellationToken A token to observe while waiting for the task to complete. Returns The rendered HTML for this stream action. Type RazorWireStreamBuilder A fluent builder for creating Turbo Stream responses. Method Append RazorWireStreamBuilder Append ( string target , string templateHtml ) Queues an append action that inserts the provided HTML into the specified target element. Parameters target The target DOM selector or element identifier to which the HTML will be appended. templateHtml The HTML fragment to append inside the target\u0027s template. Returns The same RazorWireStreamBuilder instance to allow fluent chaining. Method AppendPartial RazorWireStreamBuilder AppendPartial ( string target , string viewName , object? model = null ) Queues an action to append the rendered partial view to the specified DOM target. Parameters target The DOM target selector or element identifier where the partial will be appended. viewName The name of the partial view to render. model An optional model to pass to the partial view. Returns The current RazorWireStreamBuilder instance for fluent chaining. Method Prepend RazorWireStreamBuilder Prepend ( string target , string templateHtml ) Queues a raw HTML prepend action targeting the specified DOM element. Parameters target The DOM target selector or identifier to receive the content. templateHtml The HTML content to insert before the target element\u0027s existing content. Returns The builder instance for fluent chaining. Method PrependPartial RazorWireStreamBuilder PrependPartial ( string target , string viewName , object? model = null ) Queues an action to prepend the rendered partial view into the specified DOM target. Parameters target The DOM selector or element identifier to receive the rendered partial. viewName The name or path of the partial view to render. model The model to pass to the partial view, or null if none. Returns The current RazorWireStreamBuilder instance for fluent chaining. Method Replace RazorWireStreamBuilder Replace ( string target , string templateHtml ) Queues a raw HTML replace action targeting the specified DOM element. Parameters target The DOM element selector or identifier to target. templateHtml The HTML content used to replace the target\u0027s contents. Returns The current RazorWireStreamBuilder instance. Method ReplacePartial RazorWireStreamBuilder ReplacePartial ( string target , string viewName , object? model = null ) Queues a partial view to replace the contents of the specified DOM target with the rendered partial. Parameters target The DOM element selector or identifier to target for the replace action. viewName The name of the partial view to render. model An optional model passed to the partial view. Returns The same RazorWireStreamBuilder instance for fluent chaining. Method Update RazorWireStreamBuilder Update ( string target , string templateHtml ) Queues a raw HTML \u0022update\u0022 turbo-stream action for the specified DOM target using the provided HTML template. Parameters target The DOM target selector or identifier to apply the update to. templateHtml The HTML fragment to use as the action\u0027s template. Returns The same RazorWireStreamBuilder instance for fluent chaining. Method UpdatePartial RazorWireStreamBuilder UpdatePartial ( string target , string viewName , object? model = null ) Queues an \u0022update\u0022 turbo-stream action that renders the specified partial view into the given target element. Parameters target The DOM target selector or identifier to update. viewName The name of the partial view to render. model An optional model to pass to the partial view. Returns The builder instance for further chaining. Method AppendComponent 2 overloads RazorWireStreamBuilder AppendComponent \u003CT\u003E ( string target , object? arguments = null ) Queues an append action that will render the specified view component into the given DOM target. Type Parameters T The ViewComponent type to render. Parameters target The DOM element selector or identifier to target for the append action. arguments Optional arguments passed to the view component when rendering. Returns The same RazorWireStreamBuilder instance for fluent chaining. RazorWireStreamBuilder AppendComponent ( string target , string componentName , object? arguments = null ) Queues an \u0022append\u0022 turbo-stream action that will render the specified view component (by name) into the given target element. Parameters target The DOM element selector or identifier to target. componentName The name of the view component to render. arguments Optional arguments to pass to the view component. Returns The current RazorWireStreamBuilder instance for method chaining. Method PrependComponent 2 overloads RazorWireStreamBuilder PrependComponent \u003CT\u003E ( string target , object? arguments = null ) Queues a view component render action that will prepend the component\u0027s output into the specified DOM target. Type Parameters T The view component type to render. Parameters target The DOM target selector or identifier to prepend the component into. arguments Optional arguments passed to the view component. Returns The same RazorWireStreamBuilder instance for fluent chaining. RazorWireStreamBuilder PrependComponent ( string target , string componentName , object? arguments = null ) Queues a view component prepend action targeting a DOM element by name. Parameters target The DOM element selector or identifier to target. componentName The name of the view component to render and prepend. arguments Optional arguments to pass to the view component. Returns The current builder instance for fluent chaining. Method ReplaceComponent 2 overloads RazorWireStreamBuilder ReplaceComponent \u003CT\u003E ( string target , object? arguments = null ) Queues a view component replace action targeting the specified DOM element. Parameters target The DOM target selector or identifier to apply the replace action to. arguments Optional arguments to pass to the view component. Returns The builder instance for fluent chaining. RazorWireStreamBuilder ReplaceComponent ( string target , string componentName , object? arguments = null ) Queue a replace action that renders the specified view component by name into the given DOM target. Parameters target The DOM target selector or identifier to apply the replace action to. componentName The name of the view component to render. arguments Optional arguments to pass to the view component. Returns The same RazorWireStreamBuilder instance for fluent chaining. Method UpdateComponent 2 overloads RazorWireStreamBuilder UpdateComponent \u003CT\u003E ( string target , object? arguments = null ) Queues an \u0022update\u0022 turbo-stream action that renders the specified view component type into the given target element. Type Parameters T The view component type to render. Parameters target The DOM element selector or identifier that the turbo-stream will target. arguments Optional arguments to pass to the view component. Returns The same RazorWireStreamBuilder instance for fluent chaining. RazorWireStreamBuilder UpdateComponent ( string target , string componentName , object? arguments = null ) Queues a view component update action for a named view component. Parameters target The DOM target selector or identifier to apply the update to. componentName The name of the view component to render. arguments Optional arguments to pass to the view component. Returns The builder instance for fluent chaining. Method Remove RazorWireStreamBuilder Remove ( string target ) Queues a remove action targeting the specified DOM element. Parameters target The DOM target selector or identifier whose element will be removed. Returns The current RazorWireStreamBuilder instance for fluent chaining. Method FormError RazorWireStreamBuilder FormError ( string target , string title , string message ) Queues a form-local failure summary for an enhanced RazorWire form. Parameters target The Turbo target id whose element should receive the generated failure block. title Plain-text failure title. RazorWire HTML-encodes this value. message Plain-text failure message. RazorWire HTML-encodes this value. Returns The current RazorWireStreamBuilder instance for fluent chaining. Remarks The target value is emitted as Turbo\u0027s target attribute, so it should name the DOM element that Turbo will update, usually a form-local error container. Calling this method marks the stream as a handled form response; BuildResult(int?) will emit Forms.RazorWireFormHeaders.FormHandled so the browser runtime does not add a second fallback block for the same failed submission. Method FormValidationErrors RazorWireStreamBuilder FormValidationErrors ( string target , ModelStateDictionary modelState , string title = \u0022Please fix the highlighted fields.\u0022 , int maxErrors = 10 , string message = \u0022We could not submit this form. Check your input and try again.\u0022 ) Queues a form-local validation summary from an MVC ModelStateDictionary . Parameters target The Turbo target id whose element should receive the generated validation block. modelState The MVC model state to render into a validation summary. title Plain-text summary title. RazorWire HTML-encodes this value. maxErrors Maximum number of individual validation errors to show before an overflow line is added; values less than zero are treated as zero. message Plain-text fallback message used when the model state contains no displayable errors. Returns The current RazorWireStreamBuilder instance for fluent chaining. Remarks The target value is emitted as Turbo\u0027s target attribute, so it should name the DOM element that Turbo will update. Calling this method marks the stream as a handled form response; BuildResult(int?) will emit Forms.RazorWireFormHeaders.FormHandled so the browser runtime does not render its default fallback UI. maxErrors is clamped to zero or greater. RazorWire orders collected errors by error.Key using StringComparer.Ordinal , then renders only the first maxErrors errors and adds an overflow line when more errors were hidden. For errors that share the same field key, original model-state insertion order is preserved. When the model state has no displayable errors, the provided message is rendered as the fallback copy. Method Build string Build () Builds a single concatenated Turbo Stream markup string from the queued raw HTML actions. Returns The concatenated Turbo Stream markup representing the queued raw HTML actions. Exceptions InvalidOperationException Thrown if the builder contains actions that require asynchronous rendering (such as partial views or view components); use RenderAsync(viewContext) or BuildResult() instead. Method RenderAsync Task\u003Cstring\u003E RenderAsync ( Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext , CancellationToken cancellationToken = default ) Renders all queued stream actions using the provided ViewContext and concatenates their rendered HTML into a single string. Parameters viewContext The view rendering context to use for each action. cancellationToken Token to observe for cancellation. Returns The concatenated HTML string produced by rendering each queued action. Method BuildResult RazorWireStreamResult BuildResult ( int? statusCode = null ) Creates a RazorWireStreamResult containing the builder\u0027s queued stream actions and associated controller. Parameters statusCode Optional HTTP status code to apply to the response, commonly 422 for handled validation failures. Returns A RazorWireStreamResult initialized with a copy of the queued actions and the builder\u0027s controller. Remarks If FormError(string,string,string) or FormValidationErrors(string,ModelStateDictionary,string,int,string) was queued, the result also emits the Forms.RazorWireFormHeaders.FormHandled response header. That header is the runtime contract that prevents the package default failed-form fallback from rendering on top of server-authored UI. Type RawHtmlStreamAction Method RenderAsync Task\u003Cstring\u003E RenderAsync ( Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext , CancellationToken cancellationToken = default ) Renders the action as a turbo-stream HTML string. Parameters viewContext The rendering context used when rendering the action. cancellationToken Cancellation token (ignored for raw HTML). Returns The turbo-stream element for the action and target; for action \u0022remove\u0022 the element has no \u003Ctemplate\u003E, otherwise its \u003Ctemplate\u003E contains the action\u0027s HTML. Type TurboRequestExtensions Provides extension methods for HttpRequest to detect Turbo requests. Method IsTurboRequest bool IsTurboRequest ( this HttpRequest request ) Determines whether the request\u0027s Accept header signals a Turbo Stream response. Parameters request The HttpRequest to check. Returns true if the Accept header contains \u0022text/vnd.turbo-stream.html\u0022, otherwise false .","snippet":"Type ViewComponentStreamHelper Internal helper for rendering view components into Turbo Stream fragments. Method RenderComponentStreamAsync Task\u003Cstring\u003E RenderComponentStreamAsync ( ViewContext viewContext , string...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-IRazorPartialRenderer","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-IRazorPartialRenderer","title":"IRazorPartialRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","IRazorPartialRenderer"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-IRazorPartialRenderer"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-IRazorWireStreamAction","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-IRazorWireStreamAction","title":"IRazorWireStreamAction","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","IRazorWireStreamAction"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-IRazorWireStreamAction"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-PartialViewStreamAction","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-PartialViewStreamAction","title":"PartialViewStreamAction","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","PartialViewStreamAction"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-PartialViewStreamAction"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorPartialRenderer","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorPartialRenderer","title":"RazorPartialRenderer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","RazorPartialRenderer"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorPartialRenderer"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireBridge","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireBridge","title":"RazorWireBridge","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","RazorWireBridge"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorWireBridge"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireBridge-NullView","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireBridge-NullView","title":"NullView","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","NullView"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorWireBridge-NullView"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamBuilder","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamBuilder","title":"RazorWireStreamBuilder","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","RazorWireStreamBuilder"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorWireStreamBuilder"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamBuilder-RawHtmlStreamAction","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamBuilder-RawHtmlStreamAction","title":"RawHtmlStreamAction","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","RawHtmlStreamAction"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorWireStreamBuilder-RawHtmlStreamAction"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult","title":"RazorWireStreamResult","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","RazorWireStreamResult"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult-NullView","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult-NullView","title":"NullView","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","NullView"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult-NullView"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult-RawHtmlStreamAction","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult-RawHtmlStreamAction","title":"RawHtmlStreamAction","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","RawHtmlStreamAction"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-RazorWireStreamResult-RawHtmlStreamAction"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-TurboFrameViewModel","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-TurboFrameViewModel","title":"TurboFrameViewModel","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","TurboFrameViewModel"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-TurboFrameViewModel"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-TurboRequestExtensions","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-TurboRequestExtensions","title":"TurboRequestExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","TurboRequestExtensions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-TurboRequestExtensions"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-ViewComponentByNameStreamAction","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-ViewComponentByNameStreamAction","title":"ViewComponentByNameStreamAction","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","ViewComponentByNameStreamAction"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-ViewComponentByNameStreamAction"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-ViewComponentStreamAction","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-ViewComponentStreamAction","title":"ViewComponentStreamAction","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","ViewComponentStreamAction"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-ViewComponentStreamAction"},{"id":"Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-ViewComponentStreamHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.Bridge.html#ForgeTrust-RazorWire-Bridge-ViewComponentStreamHelper","title":"ViewComponentStreamHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Bridge","ViewComponentStreamHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Bridge#ForgeTrust-RazorWire-Bridge-ViewComponentStreamHelper"},{"id":"Namespaces/ForgeTrust.RazorWire.Caching.html","path":"/docs/Namespaces/ForgeTrust.RazorWire.Caching.html","title":"Caching","summary":"Type RazorWireOutputCachingExtensions Provides extension methods for configuring ASP.NET Core Output Caching with RazorWire policies. Method AddRazorWirePolicies OutputCacheOptions AddRazorWirePolicies ( this...","headings":["RazorWireOutputCachingExtensions","AddRazorWirePolicies"],"bodyText":"Type RazorWireOutputCachingExtensions Provides extension methods for configuring ASP.NET Core Output Caching with RazorWire policies. Method AddRazorWirePolicies OutputCacheOptions AddRazorWirePolicies ( this OutputCacheOptions options , RazorWireOptions rwOptions ) Adds two output caching policies for Razor Wire using names from rwOptions : a page policy with 1-minute expiration and an island policy with 30-second expiration, both restricted to responses for unauthenticated users. Parameters options The OutputCacheOptions instance to configure. rwOptions RazorWire configuration providing policy names. Returns The modified OutputCacheOptions instance.","snippet":"Type RazorWireOutputCachingExtensions Provides extension methods for configuring ASP.NET Core Output Caching with RazorWire policies. Method AddRazorWirePolicies OutputCacheOptions AddRazorWirePolicies ( this...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Caching"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Caching"},{"id":"Namespaces/ForgeTrust.RazorWire.Caching.html#ForgeTrust-RazorWire-Caching-RazorWireOutputCachingExtensions","path":"/docs/Namespaces/ForgeTrust.RazorWire.Caching.html#ForgeTrust-RazorWire-Caching-RazorWireOutputCachingExtensions","title":"RazorWireOutputCachingExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Caching","RazorWireOutputCachingExtensions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Caching#ForgeTrust-RazorWire-Caching-RazorWireOutputCachingExtensions"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html","title":"Cli","summary":"Type ExportDiagnostic Describes one CDN export validation problem with a stable code and actionable context. Remarks Diagnostics are immutable value objects suitable for command-line output, logs, and structured...","headings":["ExportDiagnostic","Code","Message","Route","Reference","RazorWireCliApp","RunAsync","ExportValidationException","Diagnostics","ProcessResult","ExportSourceResolver","ExecuteProcessAsync","TryResolveAssemblyNameAsync","TryResolveAssemblyNameFromXml","ListeningUrlTimeout","AppReadyTimeout","AppReadyPollInterval","ExportSourceRequestFactory","ExportMode","ExportReferenceKind","ProcessLaunchSpec","FileName","Arguments","EnvironmentOverrides"],"bodyText":"Type ExportDiagnostic Describes one CDN export validation problem with a stable code and actionable context. Remarks Diagnostics are immutable value objects suitable for command-line output, logs, and structured inspection through ExportValidationException.Diagnostics . The public contract exposes the stable code, plain-text message, and route context. Internal exporter code may attach the discovered reference that produced the diagnostic for de-duplication and richer validation decisions. Property Code string Code { get; } Gets the short machine-readable diagnostic identifier. Property Message string Message { get; } Gets the human-readable plain-text validation message. Property Route string Route { get; } Gets the root-relative route or export context where the diagnostic was produced. Property Reference ExportReference? Reference { get; } Gets the optional exporter-managed reference that produced the diagnostic. Remarks This value is internal because it is tied to crawl provenance rather than the public validation exception contract. It is null for diagnostics that describe route-level failures instead of a specific markup or CSS reference. Type RazorWireCliApp Provides the RazorWire CLI entry surface with the command-first console behavior required for public tool flows. Method RunAsync Task RunAsync ( string[] args , Action\u003CConsoleOptions\u003E? configureOptions = null ) Runs the RazorWire CLI directly through the command service while still allowing targeted startup customization. Parameters args Command-line arguments supplied to the CLI. configureOptions Optional console startup customization applied after RazorWire\u0027s defaults. Returns A task that completes when the CLI command finishes running. Remarks Public command-line tool entry points need predictable command output for help, validation errors, and export progress. Running the command service directly keeps those flows independent from the Generic Host lifecycle while preserving AppSurface\u0027s command registration, dependency injection, and unknown-option suggestions. Type ExportValidationException Represents exporter-domain validation failures that prevent CDN-safe output from being produced. Remarks The export engine throws this exception without depending on CLI infrastructure. Command handlers should translate it into the appropriate command-line failure type for their host. Property Diagnostics IReadOnlyList\u003CExportDiagnostic\u003E Diagnostics { get; } Gets the diagnostics that describe why CDN export validation failed. Type ProcessResult Structured command execution result used by the export resolver pipeline. Parameters ExitCode The process exit code, or a synthetic negative value when process start failed before an operating-system exit code was available. Stdout The captured standard output for the command. Stderr The captured standard error or a synthetic start-failure message. Remarks The resolver prefers this explicit result shape over exceptions for ordinary command failures so it can preserve stdout/stderr in logs and decide whether to throw, fall back to XML parsing, or continue probing. Type ExportSourceResolver Resolves export sources and, when needed, orchestrates launching a target application for crawling. Method ExecuteProcessAsync Task\u003CProcessResult\u003E ExecuteProcessAsync ( string fileName , IReadOnlyList\u003Cstring\u003E args , string workingDirectory , CancellationToken cancellationToken ) Executes a command through the configured ICommandExecutor . Parameters fileName The executable to start. args The ordered command-line arguments for the executable. workingDirectory The working directory used for process start. cancellationToken Cancels the command execution. Returns A ProcessResult containing the exit code and captured output streams from the delegated executor. Remarks This seam exists so resolver tests can verify command composition without launching real processes. Callers should treat a non-zero exit as data and decide whether to raise an exception or fall back. Method TryResolveAssemblyNameAsync Task\u003Cstring\u003E TryResolveAssemblyNameAsync ( string projectPath , string fallbackName , string? framework , CancellationToken cancellationToken ) Resolves the effective assembly name for a project, preferring MSBuild evaluation and falling back to raw project XML parsing when needed. Parameters projectPath The project file whose assembly name should be resolved. fallbackName The fallback assembly name when no explicit value can be determined. framework The target framework used for MSBuild evaluation. Supplying this keeps conditional AssemblyName values aligned with the publish target. cancellationToken Cancels MSBuild evaluation. Returns The assembly name reported by MSBuild when available; otherwise the value returned by TryResolveAssemblyNameFromXml . Exceptions OperationCanceledException Thrown when command execution is canceled. Remarks MSBuild is preferred because it evaluates imports and conditional properties that raw XML parsing cannot see. If MSBuild exits non-zero, produces no usable stdout, or throws a non-cancellation exception, the resolver logs the failure details and falls back to XML parsing. Omitting framework can mis-evaluate conditional AssemblyName declarations for multi-target projects. Method TryResolveAssemblyNameFromXml string TryResolveAssemblyNameFromXml ( string projectPath , string fallbackName ) Reads a project file directly and returns the first explicit AssemblyName value found in the XML. Parameters projectPath The project file to inspect. fallbackName The value returned when the XML cannot be read or has no assembly name. Returns The explicit AssemblyName from the project file, or fallbackName when no usable value is available. Remarks This method intentionally does not evaluate imports or conditional MSBuild properties. It is the low-cost fallback used when MSBuild evaluation is unavailable or fails to return a usable value. Property ListeningUrlTimeout TimeSpan ListeningUrlTimeout { get; set; } Gets or sets the maximum time to wait for the launched target app to emit a listening URL. Property AppReadyTimeout TimeSpan AppReadyTimeout { get; set; } Gets or sets the maximum time to wait for the launched target app to respond as ready. Property AppReadyPollInterval TimeSpan AppReadyPollInterval { get; set; } Gets or sets the polling interval used while probing target app readiness. Type ExportSourceRequestFactory Creates validated export source requests from CLI options. Enum ExportMode Selects how RazorWire export output should resolve internal application URLs. Remarks The default selection is Cdn . Choose Cdn for output that will be served directly by a static host or CDN. Choose Hybrid only when the exported files will still be hosted behind infrastructure that preserves application routing and dynamic server behavior. New values must only be appended so existing serialized or logged enum values remain stable. Enum ExportReferenceKind Identifies the HTML or CSS surface where an export reference was found. Type ProcessLaunchSpec Describes how to launch an external process. Property FileName string FileName { get; init; } Gets the executable file name. Property Arguments IReadOnlyList\u003Cstring\u003E Arguments { get; init; } Gets the argument tokens passed to the process. Property EnvironmentOverrides IReadOnlyDictionary\u003Cstring, string\u003E EnvironmentOverrides { get; init; } Gets environment variable overrides applied for process startup. Property WorkingDirectory string WorkingDirectory { get; init; } Gets the working directory for the process. Type ExportCommand A command for exporting a RazorWire site to a static directory. Method ExecuteAsync 2 overloads ValueTask ExecuteAsync ( IConsole console ) Executes the export process for the RazorWire site to the configured output directory, validating options and writing progress to the console. Parameters console The console used to write progress and completion messages. Returns A ValueTask that completes when the export operation finishes. ValueTask ExecuteAsync ( IConsole console , CancellationToken cancellationToken ) Executes the export process using an explicit cancellation token. Parameters console The console used to write progress and completion messages. cancellationToken Cancellation token for startup and export operations. Returns A ValueTask that completes when the export operation finishes. Property OutputPath string OutputPath { get; init; } Gets or sets the path to the directory where the exported site will be written. Defaults to \u0022dist\u0022 . Property SeedRoutesPath string? SeedRoutesPath { get; init; } Gets or sets an optional path to a plain-text file containing one initial seed route per line. Remarks This property is bound from the -r|--seeds command option. When it is null or empty, the exporter starts from the root route ( / ). When it points to a file, the exporter reads each line, accepts root-relative routes and absolute HTTP(S) URLs, strips query strings and fragments during normalization, and skips invalid, external, hash-only, JavaScript, or mailto entries. If the file is missing or unreadable, export fails and returns a non-zero CLI exit code. If the file is readable but contains no valid routes, the exporter logs a warning and falls back to the root route. Property Mode ExportMode Mode { get; init; } Gets or sets the export mode that controls whether output is rewritten for static CDN hosting. Remarks ExportMode.Cdn is the default and emits fully static output for plain static hosts. Use ExportMode.Hybrid when the exported directory will still be served behind application-style routing that can resolve extensionless URLs. Property BaseUrl string? BaseUrl { get; init; } Gets or sets the base URL of a running application to crawl. Property ProjectPath string? ProjectPath { get; init; } Gets or sets a path to a .csproj file to run and export. Property DllPath string? DllPath { get; init; } Gets or sets a path to a .dll file to run and export. Property Framework string? Framework { get; init; } Gets or sets an optional target framework for project exports, required for multi-target projects. Property AppArgs string[] AppArgs { get; init; } Gets or sets app arguments forwarded to the launched target app. Repeat this option for each token. Property NoBuild bool NoBuild { get; init; } Gets or sets a value indicating whether project mode should skip build before launch. Type ExportContext Provides context and state for an export operation, including configuration and crawl progress. Property OutputPath string OutputPath { get; } Gets the path where exported files will be saved. Property SeedRoutesPath string? SeedRoutesPath { get; } Gets the optional path to a seed routes file. Property BaseUrl string BaseUrl { get; } Gets the base URL of the source application being exported. Property Mode ExportMode Mode { get; } Gets the export mode that controls URL rewriting and validation behavior. Remarks ExportMode.Cdn is the default and rewrites exporter-managed internal URLs to emitted artifacts while validating that those managed dependencies can be served by a static host. ExportMode.Hybrid preserves application-style internal URLs for server-backed deployments that still provide routing and dynamic behavior. CDN validation and rewriting only apply to exporter-managed URLs discovered in markup and CSS; unmanaged external, JavaScript, mailto, hash-only, and data URLs are intentionally ignored rather than validated or rewritten. Property Visited HashSet\u003Cstring\u003E Visited { get; } Gets the set of URLs that have already been visited during the crawl. Property Queue Queue\u003Cstring\u003E Queue { get; } Gets the queue of URLs pending processing. Property Enqueued HashSet\u003Cstring\u003E Enqueued { get; } Gets the normalized routes that have already been scheduled for crawl processing. Remarks This set mirrors Queue membership over the lifetime of an export so duplicate reference discovery can perform O(1) scheduling checks without scanning the pending queue. Routes remain in this set after dequeue because Visited and RouteOutcomes record their terminal crawl state. Property RouteOutcomes Dictionary\u003Cstring, ExportRouteOutcome\u003E RouteOutcomes { get; } Gets route fetch outcomes keyed by normalized root-relative route. Property References List\u003CExportReference\u003E References { get; } Gets every managed internal reference discovered during the crawl, including duplicate provenance. Property Diagnostics List\u003CExportDiagnostic\u003E Diagnostics { get; } Gets CDN validation diagnostics produced for this export. Property ArtifactUrls Dictionary\u003Cstring, string\u003E ArtifactUrls { get; } Gets static-host artifact URLs keyed by normalized route. Property PartialArtifactUrls Dictionary\u003Cstring, string\u003E PartialArtifactUrls { get; } Gets generated RazorDocs partial artifact URLs keyed by their source full-page route. Type ITargetAppProcess Represents a started or startable external target application process. Method Start void Start () Starts the process and begins asynchronous output capture. Method DisposeAsync ValueTask DisposeAsync () Performs best-effort asynchronous cleanup of the started target process. Returns A task that completes after cleanup work finishes. Remarks Cleanup order is: Check HasExited against the underlying process when startup completed. If the process is still running, issue a best-effort Kill(entireProcessTree: true) and then wait up to 5 seconds for exit, even when kill throws a recoverable cleanup exception. After exit is observed, call WaitForExit() to flush redirected stdout and stderr callbacks before returning. Pitfalls: Short-lived processes can exit before their output callbacks are delivered, so disposal performs the final flush step to improve callback delivery timing. Cleanup swallows InvalidOperationException , timeout-driven OperationCanceledException , ObjectDisposedException , and recoverable kill, wait, or flush exceptions such as Win32Exception or NotSupportedException as part of best-effort disposal. Callers must not rely on guaranteed process termination; disposal can return after the 5-second timeout even if the operating system process has not fully exited. Property HasExited bool HasExited { get; } Gets a value indicating whether the process has exited. Type ITargetAppProcessFactory Creates ITargetAppProcess instances for launch specifications. Method Create ITargetAppProcess Create ( ProcessLaunchSpec spec ) Creates a new process wrapper for the provided launch spec. Parameters spec The process launch specification. Returns A process wrapper ready to start. Type TargetAppProcessFactory Default ITargetAppProcessFactory implementation. Type TargetAppProcessHooks Optional process-operation overrides for TargetAppProcess tests. Remarks These hooks exist so tests can force cleanup branches such as unsupported kill operations, synthetic exit states, or timeout handling without reflection or fragile platform-dependent child processes. Property StartOverride Action\u003CTargetAppProcess\u003E? StartOverride { get; init; } Gets or sets an optional start override used in place of Process.Start() and output-reader setup. Remarks Tests can use this to deterministically raise ITargetAppProcess.Exited and ITargetAppProcess.OutputLineReceived in a controlled order without depending on operating-system process timing. Property HasExitedOverride Func\u003CProcess, bool\u003E? HasExitedOverride { get; init; } Gets or sets an optional exit-state override used in place of Process.HasExited . Property KillProcessOverride Action\u003CProcess\u003E? KillProcessOverride { get; init; } Gets or sets an optional kill override used in place of Process.Kill(bool) . Property WaitForExitAsyncOverride Func\u003CProcess, CancellationToken, Task\u003E? WaitForExitAsyncOverride { get; init; } Gets or sets an optional asynchronous wait override used in place of Process.WaitForExitAsync(CancellationToken) . Property WaitForExitOverride Action\u003CProcess\u003E? WaitForExitOverride { get; init; } Gets or sets an optional synchronous wait override used in place of Process.WaitForExit() . Type ExportEngine A static generation engine that crawls a RazorWire application and exports its routes to CDN or hybrid static files. Method RunAsync Task RunAsync ( ExportContext context , CancellationToken cancellationToken = default ) Crawls the site starting from configured seed routes (or the root), stages the conventional reserved 404 page when available, validates CDN output when requested, and exports discovered pages, frame sources, and assets to the output path. Parameters context Export configuration and runtime state including base URL, output path, queue, and visited set. cancellationToken Token to observe for cooperative cancellation of the crawl and export operations. Returns A task that completes when the crawl and export operations have finished. Exceptions FileNotFoundException Thrown when ExportContext.SeedRoutesPath is specified but the file does not exist. Remarks If ExportContext.SeedRoutesPath is provided, the file is read and each line is validated and normalized to a root-relative route; invalid seeds are logged. If the seed file exists but yields no valid routes, the root path (\u0022/\u0022) is enqueued. If no seed file is provided, the root path is enqueued. Before crawl processing begins, the engine probes AppSurface\u0027s reserved conventional 404 route and stages 404.html when the route returns a successful HTML response. That reserved-route probe is best-effort only: failures are logged, do not abort the crawl, and do not prevent queued seed routes from being processed. Once staged, the 404.html body participates in the same CDN validation and reference rewriting as other HTML artifacts. Export then runs as a three-stage pipeline: seed queue -\u003E crawl/fetch/discover -\u003E CDN validation -\u003E materialize/rewrite The crawl stage records route outcomes, artifact URLs, and reference provenance. In CDN mode, HTML and CSS bodies are kept once until materialization so managed URLs can be rewritten after the artifact map is complete. In hybrid mode, text artifacts and binary assets are written directly to their final files and only their outcomes are retained in memory. Method CrawlRouteAsync Task CrawlRouteAsync ( HttpClient client , string route , ExportContext context , CancellationToken cancellationToken ) Fetches the HTML or asset for the specified route, records export graph metadata, and enqueues discovered managed references. Method IsDocsExportPage bool IsDocsExportPage ( string route , string html , string? docContentFrame = null ) Determines whether an exported HTML page should receive RazorDocs static partial support. Parameters route The root-relative route being exported. html The fetched HTML document. docContentFrame The extracted doc-content frame, when the caller has already parsed it. Returns true for the legacy /docs route family or HTML that carries RazorDocs runtime markers; otherwise false . Remarks Custom RazorDocs hosts can mount under route families such as /foo/bar , so export detection cannot rely only on path prefixes. The client config marker covers search and shell pages, while the content frame covers document detail pages. Method MapRouteToFilePath string MapRouteToFilePath ( string route , string outputPath , bool isHtml ) Maps a root-relative route to an absolute file path inside the configured output directory. Method ExtractLinks void ExtractLinks ( string html , ExportContext context , string currentRoute = \u0022/\u0022 ) Extracts root-relative internal link targets from the provided HTML and enqueues any unvisited routes for crawling. Parameters html HTML source to scan. context The export context. currentRoute The route used to resolve relative anchor URLs and record source provenance. Method ExtractFrames void ExtractFrames ( string html , ExportContext context , string currentRoute = \u0022/\u0022 ) Extracts root-relative \u0060src\u0060 values from \u003Cturbo-frame\u003E elements in the provided HTML and enqueues each unvisited path for export. Parameters html HTML content to scan. context The export context. currentRoute The route used to resolve relative frame source URLs and record source provenance. Method ExtractAssets void ExtractAssets ( string html , string currentRoute , ExportContext context ) Extracts root-relative asset references (scripts, styles, images) from the provided HTML and enqueues each unvisited path for export. Parameters html HTML content to scan. currentRoute The route of the page being scanned, used for resolving relative URLs. context The export context. Method ExtractReferences IReadOnlyList\u003CExportReference\u003E ExtractReferences ( string content , string currentRoute , bool htmlScope ) Extracts exporter-managed internal references from HTML or CSS content. Parameters content The HTML document, style block, style attribute, or stylesheet body to scan. currentRoute The normalized route that owns content , used to resolve relative URLs and record provenance. htmlScope true scans HTML surfaces including anchors, Turbo Frames, scripts, supported link tags, image sources, srcset candidates, style blocks, and style attributes. Anchors marked with data-rw-export-ignore , and relative anchors pointing at common source or project file extensions, are skipped so authoring-only source-navigation links can remain clickable without becoming CDN dependencies. false scans only CSS url(...) references. Returns References with managed root-relative paths only. External URLs, protocol-relative URLs, hash-only references, data URLs, JavaScript URLs, mailto links, and malformed values are filtered out before the caller enqueues or validates them. Method ResolveRelativeUrl string ResolveRelativeUrl ( string baseRoute , string url ) Resolves a potentially relative URL against a base route. Type ProgramEntryPoint Provides a testable wrapper around the RazorWire CLI top-level entrypoint. Method RunAsync Task RunAsync ( string[] args , Action\u003CConsoleOptions\u003E? configureOptions = null ) Runs the RazorWire CLI using the same command-first startup path as the shipped program entrypoint. Parameters args Command-line arguments supplied to the CLI. configureOptions Optional console startup customization applied before the CLI host starts. Returns A task that completes when CLI execution finishes. Method PushConfigureOptionsOverrideForTests IDisposable PushConfigureOptionsOverrideForTests ( Action\u003CConsoleOptions\u003E configureOptions ) Temporarily injects additional console startup configuration for the duration of a test that invokes the real assembly entrypoint. Parameters configureOptions Test-only console startup customization applied after any explicit caller configuration. Returns A disposable scope that restores the previous override when disposed. Type ExportRouteOutcome Records the fetch and materialization state for one normalized export route. Method Success 2 overloads ExportRouteOutcome Success ( string route , string? contentType , string artifactPath , string artifactUrl , string? textBody ) Creates a successful route outcome with emitted artifact details. Parameters route Normalized root-relative route that was crawled, such as / or /docs/start . contentType Response media type when known, or null when the server omitted it. artifactPath Absolute output file path written for the route. artifactUrl Static-host URL that resolves to the emitted artifact. textBody Captured HTML or CSS body retained for later validation and rewriting, or null for streamed assets. Returns An outcome with Succeeded set to true , artifact fields populated, and no status code or exception. ExportRouteOutcome Success ( string route , string? contentType , string artifactPath , string artifactUrl ) Creates a successful route outcome for an artifact whose body does not need deferred validation or rewriting. Parameters route Normalized root-relative route that was crawled, such as / or /docs/start . contentType Response media type when known, or null when the server omitted it. artifactPath Absolute output file path written for the route. artifactUrl Static-host URL that resolves to the emitted artifact. Returns An outcome with Succeeded set to true , artifact fields populated, and no retained body. Method NonSuccess ExportRouteOutcome NonSuccess ( string route , HttpStatusCode statusCode ) Creates an outcome for a route that completed at the HTTP layer with a non-success status code. Parameters route Normalized root-relative route that was crawled. statusCode HTTP status code returned by the source application. Returns An outcome with Succeeded set to false , StatusCode populated, and no artifact or exception fields. Exceptions ArgumentException Thrown when route is null, empty, or whitespace. ArgumentOutOfRangeException Thrown when statusCode is a successful 2xx HTTP status code. Method Failed ExportRouteOutcome Failed ( string route , Exception exception ) Creates an outcome for a route that failed because an exception interrupted fetch or write processing. Parameters route Normalized root-relative route that was being processed. exception Exception that prevented the route from completing. Returns An outcome with Succeeded set to false , Exception populated, and no status or artifact fields. Property Route string Route { get; } Gets the normalized root-relative route that was fetched. Property Succeeded bool Succeeded { get; } Gets a value indicating whether the route fetched successfully. Property ContentType string? ContentType { get; } Gets the response media type when one was available, optionally including media-type parameters. Property StatusCode HttpStatusCode? StatusCode { get; } Gets the non-success response status code when the fetch failed at the HTTP layer. Property ArtifactPath string? ArtifactPath { get; } Gets the absolute output file path for a successful route. Property ArtifactUrl string? ArtifactUrl { get; } Gets the static-host URL that should be used to reach the emitted artifact. Property TextBody string? TextBody { get; } Gets the fetched HTML or CSS body retained until materialization. Property Exception Exception? Exception { get; } Gets the exception that prevented the route from being fetched or written. Property IsHtml bool IsHtml { get; } Gets a value indicating whether the route was fetched as HTML. Property IsCss bool IsCss { get; } Gets a value indicating whether the route was fetched as CSS. Type RazorWireCliModule A terminal/CLI module for RazorWire providing static site export capabilities. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Configures services needed for the CLI, including the export pipeline and command-owned logging defaults. Parameters context The startup context. services The service collection to populate. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , IHostBuilder builder ) Executes pre-service host configuration; currently no implementation is required. Parameters context The startup context. builder The host builder. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , IHostBuilder builder ) Executes post-service host configuration; currently no implementation is required. Parameters context The startup context. builder The host builder. Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers dependencies for this module; currently no implementation is required. Parameters builder The module dependency builder. Type ExportReference Describes one exporter-managed internal URL discovered while crawling HTML or CSS. Remarks RawValue is the exact value found in markup or CSS. ResolvedUrl is the root-relative URL after resolving relative references against SourceRoute . Path is the query-free route used for fetch de-duplication, while Query and Fragment preserve the original URL shape for CDN validation and rewriting decisions. Property IsAsset bool IsAsset { get; } Gets a value indicating whether the reference points at an asset-like dependency rather than a page route. Type CommandExecutor Default ICommandExecutor implementation backed by Process . Remarks This implementation models launch failures as ProcessResult instances instead of throwing so resolver code can treat command execution as data and decide whether to fall back or raise a richer exception. If the command is canceled after launch starts, cancellation is propagated and the finally block still attempts to stop the child process tree. Method ExecuteCommandAsync Task\u003CProcessResult\u003E ExecuteCommandAsync ( string fileName , IReadOnlyList\u003Cstring\u003E args , string workingDirectory , CancellationToken cancellationToken ) Starts a child process, captures its output streams, and returns the resulting ProcessResult . Parameters fileName The executable to launch. args The ordered command-line arguments passed to the executable. workingDirectory The working directory supplied to the process start info. cancellationToken Cancels the process wait and output reads. Returns A ProcessResult whose fields contain the exit code, stdout, and stderr on success, or a synthetic failure result when the process cannot be started. Exceptions OperationCanceledException Thrown when cancellation is observed after launch begins. Remarks The method intentionally returns ProcessResult for launch/setup failures so callers can preserve command context in their own diagnostics. The finally block always attempts Kill(entireProcessTree: true) for started processes, so callers should assume cancellation or mid-flight failures may terminate child processes spawned by the launched command. Type ICommandExecutor Executes child processes for the export pipeline while preserving a structured ProcessResult contract for callers. Remarks This abstraction exists so resolver logic can verify command composition without launching real processes in tests. Callers should prefer it whenever they need stdout, stderr, exit code, and cancellation behavior surfaced in a consistent shape. Method ExecuteCommandAsync Task\u003CProcessResult\u003E ExecuteCommandAsync ( string fileName , IReadOnlyList\u003Cstring\u003E args , string workingDirectory , CancellationToken cancellationToken ) Executes a command and captures its exit code, standard output, and standard error. Parameters fileName The executable to start. args The ordered command-line arguments passed to fileName . workingDirectory The working directory used for process start. cancellationToken Cancels the launched process and any in-flight output reads. Returns A ProcessResult whose ExitCode , Stdout , and Stderr describe the completed command or a start-up failure. Remarks Implementations should avoid throwing for ordinary process start failures so higher-level callers can decide whether to surface an exception, retry, or fall back. Cancellation should still propagate via OperationCanceledException .","snippet":"Type ExportDiagnostic Describes one CDN export validation problem with a stable code and actionable context. Remarks Diagnostics are immutable value objects suitable for command-line output, logs, and structured...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-CommandExecutor","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-CommandExecutor","title":"CommandExecutor","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","CommandExecutor"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-CommandExecutor"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportCommand","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportCommand","title":"ExportCommand","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportCommand"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportCommand"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportContext","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportContext","title":"ExportContext","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportContext"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportContext"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportDiagnostic","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportDiagnostic","title":"ExportDiagnostic","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportDiagnostic"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportDiagnostic"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportEngine","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportEngine","title":"ExportEngine","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportEngine"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportEngine"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportMode","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportMode","title":"ExportMode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportMode"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportMode"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportReference","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportReference","title":"ExportReference","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportReference"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportReference"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportReferenceKind","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportReferenceKind","title":"ExportReferenceKind","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportReferenceKind"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportReferenceKind"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportRouteOutcome","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportRouteOutcome","title":"ExportRouteOutcome","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportRouteOutcome"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportRouteOutcome"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportSourceRequestFactory","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportSourceRequestFactory","title":"ExportSourceRequestFactory","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportSourceRequestFactory"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportSourceRequestFactory"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportSourceResolver","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportSourceResolver","title":"ExportSourceResolver","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportSourceResolver"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportSourceResolver"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportValidationException","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ExportValidationException","title":"ExportValidationException","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ExportValidationException"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ExportValidationException"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ICommandExecutor","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ICommandExecutor","title":"ICommandExecutor","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ICommandExecutor"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ICommandExecutor"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ITargetAppProcess","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ITargetAppProcess","title":"ITargetAppProcess","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ITargetAppProcess"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ITargetAppProcess"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ITargetAppProcessFactory","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ITargetAppProcessFactory","title":"ITargetAppProcessFactory","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ITargetAppProcessFactory"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ITargetAppProcessFactory"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ProcessLaunchSpec","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ProcessLaunchSpec","title":"ProcessLaunchSpec","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ProcessLaunchSpec"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ProcessLaunchSpec"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ProcessResult","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ProcessResult","title":"ProcessResult","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ProcessResult"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ProcessResult"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ProgramEntryPoint","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-ProgramEntryPoint","title":"ProgramEntryPoint","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","ProgramEntryPoint"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-ProgramEntryPoint"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-RazorWireCliApp","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-RazorWireCliApp","title":"RazorWireCliApp","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","RazorWireCliApp"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-RazorWireCliApp"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-RazorWireCliModule","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-RazorWireCliModule","title":"RazorWireCliModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","RazorWireCliModule"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-RazorWireCliModule"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-TargetAppProcessFactory","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-TargetAppProcessFactory","title":"TargetAppProcessFactory","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","TargetAppProcessFactory"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-TargetAppProcessFactory"},{"id":"Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-TargetAppProcessHooks","path":"/docs/Namespaces/ForgeTrust.RazorWire.Cli.html#ForgeTrust-RazorWire-Cli-TargetAppProcessHooks","title":"TargetAppProcessHooks","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Cli","TargetAppProcessHooks"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Cli#ForgeTrust-RazorWire-Cli-TargetAppProcessHooks"},{"id":"Namespaces/ForgeTrust.RazorWire.Forms.html","path":"/docs/Namespaces/ForgeTrust.RazorWire.Forms.html","title":"Forms","summary":"Type RazorWireEventIds Defines stable event identifiers for RazorWire form-related logs. Type RazorWireFormHeaders Defines stable HTTP header names used by RazorWire-enhanced form submissions. Type...","headings":["RazorWireEventIds","RazorWireFormHeaders","RazorWireFormRequestClassifier","IsRazorWireFormRequestAsync","RazorWireFormFields","RazorWireFormFailureTarget","TryNormalizeIdTarget","RazorWireAntiforgeryFailureFilter","OnResultExecutionAsync","Order"],"bodyText":"Type RazorWireEventIds Defines stable event identifiers for RazorWire form-related logs. Type RazorWireFormHeaders Defines stable HTTP header names used by RazorWire-enhanced form submissions. Type RazorWireFormRequestClassifier Detects whether an incoming request originated from a RazorWire-enhanced form. Method IsRazorWireFormRequestAsync ValueTask\u003Cbool\u003E IsRazorWireFormRequestAsync ( HttpRequest request , CancellationToken cancellationToken = default ) Determines whether a request carries RazorWire form markers. Parameters request The HTTP request to inspect. cancellationToken Token used when fallback URL-encoded form parsing is required. Returns true when the request has the RazorWire form header, an already-parsed marker field, or a safely readable URL-encoded marker field; otherwise false . Type RazorWireFormFields Defines stable hidden field names used by RazorWire-enhanced form submissions. Type RazorWireFormFailureTarget Normalizes form failure targets that can be addressed safely by server-generated Turbo Streams. Method TryNormalizeIdTarget bool TryNormalizeIdTarget ( string? failureTarget , out string normalized ) Attempts to normalize a simple element-id target for a failed RazorWire form. Parameters failureTarget The value supplied by data-rw-form-failure-target . A leading # is accepted and removed. normalized When this method returns true , contains the id without a leading # . Returns true when failureTarget is a non-empty element id; otherwise false . CSS selector-like values that start with . or [ , and values containing whitespace, are rejected because server-generated Turbo Stream target attributes address one element id rather than arbitrary selectors. Type RazorWireAntiforgeryFailureFilter Converts RazorWire form anti-forgery validation failures into handled responses that Turbo can render in-place. Remarks The filter runs late in MVC result execution so it can see IAntiforgeryValidationFailedResult results produced by MVC anti-forgery validation. It only rewrites requests classified as RazorWire forms, sets RazorWireFormHeaders.FormHandled , and chooses Turbo Stream, HTML, or plain-text output from the request\u0027s Accept header. Turbo Stream responses prefer a form-local target when the posted marker can be read within the configured safety limit; otherwise they append one safe diagnostic block to body . Method OnResultExecutionAsync Task OnResultExecutionAsync ( ResultExecutingContext context , ResultExecutionDelegate next ) Rewrites RazorWire anti-forgery validation failures into handled form responses, then continues result execution. Parameters context The MVC result-executing context. next Delegate that continues MVC result execution. Returns A task that completes when the result pipeline has continued. Property Order int Order { get; } Gets the filter order. The value runs after normal MVC result filters while still leaving a small buffer for application filters that intentionally need to run later.","snippet":"Type RazorWireEventIds Defines stable event identifiers for RazorWire form-related logs. Type RazorWireFormHeaders Defines stable HTTP header names used by RazorWire-enhanced form submissions. Type...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Forms"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Forms"},{"id":"Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireAntiforgeryFailureFilter","path":"/docs/Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireAntiforgeryFailureFilter","title":"RazorWireAntiforgeryFailureFilter","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Forms","RazorWireAntiforgeryFailureFilter"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Forms#ForgeTrust-RazorWire-Forms-RazorWireAntiforgeryFailureFilter"},{"id":"Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireEventIds","path":"/docs/Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireEventIds","title":"RazorWireEventIds","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Forms","RazorWireEventIds"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Forms#ForgeTrust-RazorWire-Forms-RazorWireEventIds"},{"id":"Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormFailureTarget","path":"/docs/Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormFailureTarget","title":"RazorWireFormFailureTarget","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Forms","RazorWireFormFailureTarget"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Forms#ForgeTrust-RazorWire-Forms-RazorWireFormFailureTarget"},{"id":"Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormFields","path":"/docs/Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormFields","title":"RazorWireFormFields","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Forms","RazorWireFormFields"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Forms#ForgeTrust-RazorWire-Forms-RazorWireFormFields"},{"id":"Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormHeaders","path":"/docs/Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormHeaders","title":"RazorWireFormHeaders","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Forms","RazorWireFormHeaders"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Forms#ForgeTrust-RazorWire-Forms-RazorWireFormHeaders"},{"id":"Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormRequestClassifier","path":"/docs/Namespaces/ForgeTrust.RazorWire.Forms.html#ForgeTrust-RazorWire-Forms-RazorWireFormRequestClassifier","title":"RazorWireFormRequestClassifier","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Forms","RazorWireFormRequestClassifier"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Forms#ForgeTrust-RazorWire-Forms-RazorWireFormRequestClassifier"},{"id":"Namespaces/ForgeTrust.RazorWire.html","path":"/docs/Namespaces/ForgeTrust.RazorWire.html","title":"RazorWire","summary":"Namespaces Bridge Caching Cli Forms Streams TagHelpers Type ExampleJsInterop Provides an example of how JavaScript functionality can be wrapped in a .NET class for easy consumption. Parameters jsRuntime The JS runtime...","headings":["ExampleJsInterop","Prompt","DisposeAsync","RazorWireOptions","Default","Streams","Caching","Forms","RazorWireStreamOptions","BasePath","RazorWireCacheOptions","PagePolicyName","IslandPolicyName","RazorWireFormOptions","EnableFailureUx","FailureMode","EnableDevelopmentDiagnostics","DefaultFailureMessage","RazorWireFormFailureMode","RazorWireEndpointRouteBuilderExtensions","MapRazorWire","RazorWireControllerExtensions","RazorWireStream","RazorWireServiceCollectionExtensions"],"bodyText":"Namespaces Bridge Caching Cli Forms Streams TagHelpers Type ExampleJsInterop Provides an example of how JavaScript functionality can be wrapped in a .NET class for easy consumption. Parameters jsRuntime The JS runtime used to invoke JavaScript functions. Method Prompt ValueTask\u003Cstring?\u003E Prompt ( string message ) Shows a browser prompt dialog with the specified message and returns the user\u0027s input as a string, or null if the dialog was dismissed. Parameters message The message to display in the prompt dialog. Returns The user\u0027s input as a string, or null if the dialog was dismissed. Method DisposeAsync ValueTask DisposeAsync () Disposes the loaded JavaScript module and releases associated JS resources. Remarks If the module was never loaded, this method completes without action. Type RazorWireOptions Represents configuration options for the RazorWire real-time streaming and caching system. Property Default RazorWireOptions Default { get; } Gets a default instance of RazorWireOptions with default configuration settings. Property Streams RazorWireStreamOptions Streams { get; } Gets configuration options for real-time streams, such as the base path for stream connections. Property Caching RazorWireCacheOptions Caching { get; } Gets configuration options for output caching policies used by RazorWire. Property Forms RazorWireFormOptions Forms { get; } Gets configuration options for RazorWire-enhanced form submissions. Type RazorWireStreamOptions Represents configuration options for RazorWire real-time streams. Property BasePath string BasePath { get; set; } Gets or sets the base path used for establishing stream connections. Defaults to \u0022/_rw/streams\u0022 . Type RazorWireCacheOptions Represents configuration options for RazorWire output caching. Property PagePolicyName string PagePolicyName { get; set; } Gets or sets the name of the output cache policy for full pages. Defaults to \u0022rw-page\u0022 . Property IslandPolicyName string IslandPolicyName { get; set; } Gets or sets the name of the output cache policy for individual islands. Defaults to \u0022rw-island\u0022 . Type RazorWireFormOptions Represents configuration options for failed rw-active form submissions. Remarks These options control the package convention for server failures from enhanced forms. The global EnableFailureUx switch has highest precedence: when it is false , RazorWire skips request markers, runtime lifecycle events, default fallback rendering, and development anti-forgery diagnostics even if FailureMode or a form-level attribute asks for them. Leave the global switch enabled and use FailureMode or per-form data-rw-form-failure values when an app wants more targeted behavior. Property EnableFailureUx bool EnableFailureUx { get; set; } Gets or sets a value indicating whether RazorWire emits failed-form request markers, lifecycle hooks, and default failure behavior. Defaults to true . Remarks Set this to false only when the host app owns all failed-form UX. It is a hard kill switch and overrides FailureMode plus any per-form data-rw-form-failure setting. Property FailureMode RazorWireFormFailureMode FailureMode { get; set; } Gets or sets the package-level failed-form behavior. Defaults to RazorWireFormFailureMode.Auto . Remarks Use RazorWireFormFailureMode.Auto for convention-over-configuration fallback UI, RazorWireFormFailureMode.Manual when the app listens to events and renders its own UI, and RazorWireFormFailureMode.Off when forms should opt into failure handling one at a time. Property EnableDevelopmentDiagnostics bool EnableDevelopmentDiagnostics { get; set; } Gets or sets a value indicating whether development-only diagnostics may be shown. Defaults to true ; diagnostics are still emitted only when the host is running in Development. Remarks Diagnostics appear only when failed-form UX is enabled, the app runs in Development, and the failure path can be identified as a RazorWire form request. Production responses stay generic even when this property is true . Property DefaultFailureMessage string DefaultFailureMessage { get; set; } Gets or sets the safe default message used for generic failed form submissions. Remarks Null, empty, and whitespace-only assignments are normalized back to RazorWire\u0027s safe fallback copy. Use a non-empty value for product-specific recovery language. Enum RazorWireFormFailureMode Defines the package-level failed-form behavior for rw-active forms. Remarks This enum only applies when RazorWireFormOptions.EnableFailureUx is enabled. Per-form data-rw-form-failure values may narrow behavior for a specific form, but the global kill switch always wins. The numeric values are explicit because this public enum may be persisted, serialized, or bound by applications. New values should be appended without changing the values documented here. Type RazorWireEndpointRouteBuilderExtensions Provides extension methods for IEndpointRouteBuilder to map RazorWire endpoints. Method MapRazorWire IEndpointRouteBuilder MapRazorWire ( this IEndpointRouteBuilder endpoints ) Registers a Server-Sent Events (SSE) GET endpoint at the configured streams base path that streams messages for a named channel. Parameters endpoints The endpoint route builder to configure. Returns The original IEndpointRouteBuilder instance. Remarks The endpoint enforces channel subscription authorization, streams hub messages as SSE (each line emitted as a \u0060data:\u0060 event), sends a 20-second heartbeat comment when idle, and unsubscribes on client disconnect. Type RazorWireControllerExtensions Provides extension methods for MVC controllers to interact with RazorWire. Method RazorWireStream RazorWireStreamBuilder RazorWireStream ( this Controller controller ) Creates a RazorWireStreamBuilder bound to the specified controller. Parameters controller The controller instance used to initialize the builder. Returns A RazorWireStreamBuilder configured to operate with the given controller. Type RazorWireServiceCollectionExtensions Provides extension methods for registering RazorWire services into the IServiceCollection . Method AddRazorWire IServiceCollection AddRazorWire ( this IServiceCollection services , Action\u003CRazorWireOptions\u003E? configure = null ) Registers RazorWire options and default RazorWire services, including IRazorPartialRenderer , into the provided IServiceCollection . Parameters services The service collection to register RazorWire services into. configure Optional action to configure RazorWireOptions ; if null, default options are used. Returns The same IServiceCollection instance with RazorWire registrations added. Type RazorWireWebModule A web module that integrates RazorWire real-time streaming and output caching into the application. Method ConfigureWebOptions void ConfigureWebOptions ( StartupContext context , WebOptions options ) Ensures the application\u0027s MVC support level is at least ControllersWithViews. Parameters context The startup context for the web module. options Web options to configure; may be modified to raise Mvc.MvcSupportLevel to ControllersWithViews if it is lower. Method ConfigureServices void ConfigureServices ( StartupContext context , IServiceCollection services ) Registers RazorWire services, enables output caching, and configures output cache options to include RazorWire policies. Parameters context The startup context for the current module initialization. services The service collection to which RazorWire, output caching, and related options are added. Method RegisterDependentModules void RegisterDependentModules ( ModuleDependencyBuilder builder ) Registers this module\u0027s dependencies with the provided dependency builder. Parameters builder The dependency builder used to declare other modules this module requires. Method ConfigureHostBeforeServices void ConfigureHostBeforeServices ( StartupContext context , Microsoft.Extensions.Hosting.IHostBuilder builder ) Executes module-specific host configuration before application services are registered. Parameters context The startup context providing environment and configuration for module initialization. builder The host builder to apply pre-service host configuration to. Remarks The default implementation does nothing. Method ConfigureHostAfterServices void ConfigureHostAfterServices ( StartupContext context , Microsoft.Extensions.Hosting.IHostBuilder builder ) Provides a hook to modify the host builder after services have been registered. Parameters context Startup context containing environment and module information. builder The Microsoft.Extensions.Hosting.IHostBuilder to configure. Method ConfigureWebApplication void ConfigureWebApplication ( StartupContext context , IApplicationBuilder app ) Enables output caching in the application\u0027s request pipeline. Parameters context Startup context providing environment and configuration for module initialization. app Application builder used to configure the HTTP request pipeline. Method ConfigureEndpoints void ConfigureEndpoints ( StartupContext context , IEndpointRouteBuilder endpoints ) Maps RazorWire HTTP endpoints into the application\u0027s endpoint route builder. Parameters context The startup context providing environment and configuration for module initialization. endpoints The endpoint route builder to which RazorWire routes will be added. Remarks In addition to the streaming endpoints, this maps assembly-embedded fallbacks for RazorWire\u0027s runtime scripts and package demo assets. Normal ASP.NET Core static web assets still serve these files first when their manifest is available; the endpoint fallback keeps package-hosted tools working when only compiled assemblies are present. Property IncludeAsApplicationPart bool IncludeAsApplicationPart { get; } Gets a value indicating whether this module\u0027s assembly should be searched for MVC application parts. Returns true for RazorWire to enable its tag helpers and other components. Type StringUtils Provides utility methods for string manipulation, specifically for generating safe identifiers. Method ToSafeId string ToSafeId ( string? input , bool appendHash = false ) Produces a safe identifier by replacing disallowed characters with hyphens, collapsing consecutive hyphens, trimming edge hyphens, and defaulting to \u0022id\u0022 for null, whitespace, or empty results. Optionally appends a short deterministic 4-character lowercase hex hash (prefixed with a hyphen) derived from the original input to ensure uniqueness. Parameters input The source string to convert into a safe identifier. appendHash If true, appends a short deterministic 4-character lowercase hex hash (prefixed with a hyphen). Returns The sanitized identifier; if appendHash is true the value is suffixed with \u0022-\u0022 and a 4-character lowercase hex hash. Method GetDeterministicHash string GetDeterministicHash ( string input ) Produces a short deterministic 4-character lowercase hexadecimal string derived from the SHA-256 hash of the input. Parameters input The string to hash. Returns A 4-character lowercase hexadecimal string. Remarks Returns only the first 4 hex characters (16 bits) of the SHA-256 digest; collisions are possible.","snippet":"Namespaces Bridge Caching Cli Forms Streams TagHelpers Type ExampleJsInterop Provides an example of how JavaScript functionality can be wrapped in a .NET class for easy consumption. Parameters jsRuntime The JS runtime...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire"],"sourcePath":"Namespaces/ForgeTrust.RazorWire"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-ExampleJsInterop","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-ExampleJsInterop","title":"ExampleJsInterop","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","ExampleJsInterop"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-ExampleJsInterop"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireCacheOptions","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireCacheOptions","title":"RazorWireCacheOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireCacheOptions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireCacheOptions"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireControllerExtensions","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireControllerExtensions","title":"RazorWireControllerExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireControllerExtensions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireControllerExtensions"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireEndpointRouteBuilderExtensions","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireEndpointRouteBuilderExtensions","title":"RazorWireEndpointRouteBuilderExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireEndpointRouteBuilderExtensions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireEndpointRouteBuilderExtensions"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireFormFailureMode","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireFormFailureMode","title":"RazorWireFormFailureMode","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireFormFailureMode"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireFormFailureMode"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireFormOptions","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireFormOptions","title":"RazorWireFormOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireFormOptions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireFormOptions"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireOptions","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireOptions","title":"RazorWireOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireOptions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireOptions"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireServiceCollectionExtensions","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireServiceCollectionExtensions","title":"RazorWireServiceCollectionExtensions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireServiceCollectionExtensions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireServiceCollectionExtensions"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireStreamOptions","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireStreamOptions","title":"RazorWireStreamOptions","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireStreamOptions"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireStreamOptions"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireWebModule","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-RazorWireWebModule","title":"RazorWireWebModule","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","RazorWireWebModule"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-RazorWireWebModule"},{"id":"Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-StringUtils","path":"/docs/Namespaces/ForgeTrust.RazorWire.html#ForgeTrust-RazorWire-StringUtils","title":"StringUtils","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","StringUtils"],"sourcePath":"Namespaces/ForgeTrust.RazorWire#ForgeTrust-RazorWire-StringUtils"},{"id":"Namespaces/ForgeTrust.RazorWire.Streams.html","path":"/docs/Namespaces/ForgeTrust.RazorWire.Streams.html","title":"Streams","summary":"Type IRazorWireStreamHub Defines the contract for a message hub that supports pub/sub operations over named channels. Method PublishAsync ValueTask PublishAsync ( string channel , string message ) Publishes a string...","headings":["IRazorWireStreamHub","PublishAsync","Subscribe","Unsubscribe","IRazorWireChannelAuthorizer","CanSubscribeAsync","DefaultRazorWireChannelAuthorizer","InMemoryRazorWireStreamHub"],"bodyText":"Type IRazorWireStreamHub Defines the contract for a message hub that supports pub/sub operations over named channels. Method PublishAsync ValueTask PublishAsync ( string channel , string message ) Publishes a string message to the specified channel. Parameters channel The name of the channel to publish the message to. message The message payload to publish. Returns A ValueTask that completes when the publish operation has finished. Method Subscribe ChannelReader\u003Cstring\u003E Subscribe ( string channel ) Subscribes to a named message channel and provides a reader for incoming messages. Parameters channel The name of the channel to subscribe to. Returns A ChannelReader{String} that yields messages published to the specified channel; the reader completes when the subscription is removed or the hub shuts down. Method Unsubscribe void Unsubscribe ( string channel , ChannelReader\u003Cstring\u003E reader ) Unsubscribes the specified reader from the named channel so it no longer receives messages from that channel. Parameters channel The name of the channel to unsubscribe from. reader The ChannelReader\u003Cstring\u003E instance to detach from the channel. Type IRazorWireChannelAuthorizer Defines the contract for authorizing subscription requests to RazorWire channels. Method CanSubscribeAsync ValueTask\u003Cbool\u003E CanSubscribeAsync ( HttpContext context , string channel ) Determines whether the current HTTP request is permitted to subscribe to the specified channel. Parameters context The current HTTP context for the subscription request. channel The name of the channel to subscribe to. Returns true if subscription is permitted, false otherwise. Type DefaultRazorWireChannelAuthorizer Provides a default implementation of IRazorWireChannelAuthorizer that permits all subscriptions. Method CanSubscribeAsync ValueTask\u003Cbool\u003E CanSubscribeAsync ( HttpContext context , string channel ) Determine whether the request represented by the context may subscribe to the specified channel. Parameters context The HTTP context of the requesting client. channel The name of the channel to subscribe to. Returns \u0060true\u0060 if subscription is allowed, \u0060false\u0060 otherwise. Remarks SECURITY WARNING: This default implementation allows ALL subscriptions to ANY channel. It is intended for development and prototyping only. In a production environment, you should replace this service with an implementation that enforces your application\u0027s specific authorization rules (e.g., checking user claims or roles). Type InMemoryRazorWireStreamHub Provides an in-memory implementation of IRazorWireStreamHub using Channel{T} for message distribution. Method PublishAsync ValueTask PublishAsync ( string channel , string message ) Publishes a message to all subscribers of the specified channel. Any subscribers that are closed or unable to accept the message are removed during the process. Parameters channel The name of the channel to publish to. message The message payload to deliver to subscribers. Returns \u0060ValueTask.CompletedTask\u0060 on success, or a faulted \u0060ValueTask\u0060 containing the exception if publishing failed. Method Subscribe ChannelReader\u003Cstring\u003E Subscribe ( string channel ) Subscribes to a named channel and returns a reader that receives messages published to that channel. The subscription uses an in-memory bounded buffer with capacity 100 that drops the oldest messages when full. Parameters channel The name of the channel to subscribe to. Returns A ChannelReader{String} that yields messages published to the specified channel until the subscription is removed or the writer is completed. Method Unsubscribe void Unsubscribe ( string channel , ChannelReader\u003Cstring\u003E reader ) Unregisters a subscriber from the specified channel and completes its associated writer. Parameters channel The name of the channel to remove the subscriber from. reader The subscriber\u0027s ChannelReader{String} ; its paired writer will be completed and removed from channel tracking.","snippet":"Type IRazorWireStreamHub Defines the contract for a message hub that supports pub/sub operations over named channels. Method PublishAsync ValueTask PublishAsync ( string channel , string message ) Publishes a string...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Streams"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Streams"},{"id":"Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-DefaultRazorWireChannelAuthorizer","path":"/docs/Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-DefaultRazorWireChannelAuthorizer","title":"DefaultRazorWireChannelAuthorizer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Streams","DefaultRazorWireChannelAuthorizer"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Streams#ForgeTrust-RazorWire-Streams-DefaultRazorWireChannelAuthorizer"},{"id":"Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-InMemoryRazorWireStreamHub","path":"/docs/Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-InMemoryRazorWireStreamHub","title":"InMemoryRazorWireStreamHub","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Streams","InMemoryRazorWireStreamHub"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Streams#ForgeTrust-RazorWire-Streams-InMemoryRazorWireStreamHub"},{"id":"Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-IRazorWireChannelAuthorizer","path":"/docs/Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-IRazorWireChannelAuthorizer","title":"IRazorWireChannelAuthorizer","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Streams","IRazorWireChannelAuthorizer"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Streams#ForgeTrust-RazorWire-Streams-IRazorWireChannelAuthorizer"},{"id":"Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-IRazorWireStreamHub","path":"/docs/Namespaces/ForgeTrust.RazorWire.Streams.html#ForgeTrust-RazorWire-Streams-IRazorWireStreamHub","title":"IRazorWireStreamHub","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","Streams","IRazorWireStreamHub"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.Streams#ForgeTrust-RazorWire-Streams-IRazorWireStreamHub"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html","title":"TagHelpers","summary":"Type AutoAssetVersioningTagHelper A TagHelper that automatically applies version hashing to script and link tags that reference local files, if the asp-append-version attribute is missing. Method IsLocal bool IsLocal...","headings":["AutoAssetVersioningTagHelper","IsLocal","ViewContext","StreamSourceTagHelper","Process","Channel","Permanent","RequiresStreamTagHelper","RequiresStream","RazorWireFormTagHelper","Enabled","TargetFrame","RazorWireScriptsTagHelper","IslandTagHelper","Id","Src","Loading","Swr","TransitionName","Export","ClientModule","ClientStrategy","ClientProps","LocalTimeTagHelper"],"bodyText":"Type AutoAssetVersioningTagHelper A TagHelper that automatically applies version hashing to script and link tags that reference local files, if the asp-append-version attribute is missing. Method IsLocal bool IsLocal ( string? path ) Determines if the provided path is a local path suitable for versioning. Parameters path The path to check. Returns true if the path is local (starts with \u0027/\u0027 or \u0027~\u0027) and is not protocol-relative; otherwise, false . Remarks Relative paths (e.g. \u0022css/site.css\u0022) are excluded because they are ambiguous without knowing the current request path context, which complicates server-side resolution. Use root-relative (\u0027/\u0027) or app-relative (\u0027~\u0027) paths for automatic versioning. Property ViewContext ViewContext ViewContext { get; set; } Gets or sets the view context. Remarks This property is automatically set by the framework when the TagHelper is created. Type StreamSourceTagHelper Tag helper that renders an rw-stream-source element to establish a connection to a RazorWire stream. Method Process void Process ( TagHelperContext context , TagHelperOutput output ) Configures the rw-stream-source element by setting its src attribute and handling the permanent option. Parameters context Contains information associated with the current HTML tag. output A stateful HTML element used to generate an HTML tag. Exceptions InvalidOperationException Thrown when Channel is null, empty, or contains only whitespace. Property Channel string Channel { get; set; } Gets or sets the channel name of the stream to connect to. This attribute is required. Property Permanent bool Permanent { get; set; } Gets or sets a value indicating whether the stream source should be preserved across Turbo page loads. Type RequiresStreamTagHelper A TagHelper that marks an element as requiring a specific Turbo Stream to be established before becoming active. Method Process void Process ( TagHelperContext context , TagHelperOutput output ) Applies stream-requirement attributes and disables the element when a requires-stream value is present. Remarks If RequiresStream is null or whitespace, the output is left unchanged. Otherwise adds the following attributes to the element: data-rw-requires-stream set to the RequiresStream value aria-disabled to \u0022true\u0022 disabled to \u0022disabled\u0022 (only for supported form elements) The element is therefore disabled until client-side code removes or updates these attributes. Property RequiresStream string? RequiresStream { get; set; } Gets or sets the name or identifier of the stream required by this element. Type RazorWireFormTagHelper A Tag Helper that enhances a standard \u003Cform\u003E element with RazorWire/Turbo features. Method Process void Process ( TagHelperContext context , TagHelperOutput output ) Processes a form tag by removing attributes that start with \u0022rw-\u0022 and configuring Turbo attributes based on the tag helper\u0027s properties. Parameters context The context for the current tag helper execution. output The tag helper output whose attributes will be modified. Property Enabled bool Enabled { get; set; } Gets or sets a value indicating whether RazorWire/Turbo enhancement is enabled for this form. Defaults to true . Property TargetFrame string? TargetFrame { get; set; } Gets or sets the identifier of the Turbo Frame that this form should target. Type RazorWireScriptsTagHelper Tag helper for rendering the necessary RazorWire scripts. Method Process void Process ( TagHelperContext context , TagHelperOutput output ) Renders the client-side script tags required by RazorWire and removes the wrapper element so no enclosing tag is emitted. Parameters context The current tag helper context. output The tag helper output that will be modified to contain the script elements and have no wrapper tag. Property ViewContext ViewContext ViewContext { get; set; } Gets or sets the view context. Type IslandTagHelper A TagHelper that renders a Turbo Frame as a \u0022RazorWire Island\u0022, enabling partial page updates and client-side module mounting. Method Process void Process ( TagHelperContext context , TagHelperOutput output ) Renders a \u003Cturbo-frame\u003E element whose attributes are populated from the tag helper\u0027s properties. Exceptions ArgumentException Thrown when Id is null, empty, or consists only of white-space characters. Remarks Validates that Id is not null, empty, or whitespace and sets attributes such as id, src, loading, data-turbo-permanent, data-rw-swr, style (view-transition-name), data-rw-export, and client-related data attributes when the corresponding properties are provided. Property Id string Id { get; set; } The unique identifier for the island, which becomes the id of the rendered turbo-frame. Property Src string? Src { get; set; } The source URL for the turbo-frame content. Property Loading string? Loading { get; set; } The loading strategy for the turbo-frame (e.g., \u0022eager\u0022, \u0022lazy\u0022). Property Permanent bool Permanent { get; set; } If true, the rendered element will have the \u0027data-turbo-permanent\u0027 attribute. Property Swr bool Swr { get; set; } If true, enables Stale-While-Revalidate behavior via \u0027data-rw-swr\u0027. Property TransitionName string? TransitionName { get; set; } The name for the CSS View Transition, applied as \u0027view-transition-name\u0027 in the style attribute. Property Export string? Export { get; set; } The name of the client-side module to export/expose. Property ClientModule string? ClientModule { get; set; } The path to the client-side module to mount on this island. Property ClientStrategy string? ClientStrategy { get; set; } The mounting strategy for the client module (e.g., \u0022load\u0022, \u0022visible\u0022, \u0022idle\u0022). Property ClientProps string? ClientProps { get; set; } Initial properties (JSON) to pass to the client module\u0027s mount function. Type LocalTimeTagHelper Tag helper that renders a \u003Ctime\u003E element with a UTC timestamp for client-side time formatting. Remarks When rw-type=\u0022local\u0022 , the JavaScript runtime formats the timestamp to the user\u0027s local timezone. When rw-type=\u0022utc\u0022 , the timestamp is formatted in UTC. Example \u003Ctime rw-type=\u0022local\u0022 datetime=\u0022@Model.Timestamp\u0022\u003E\u003C/time\u003E \u003Ctime rw-type=\u0022local\u0022 datetime=\u0022@Model.Timestamp\u0022 rw-display=\u0022relative\u0022\u003E\u003C/time\u003E \u003Ctime rw-type=\u0022local\u0022 datetime=\u0022@Model.Timestamp\u0022 rw-display=\u0022datetime\u0022 rw-format=\u0022short\u0022\u003E\u003C/time\u003E \u003Ctime rw-type=\u0022utc\u0022 datetime=\u0022@Model.Timestamp\u0022\u003E\u003C/time\u003E Method Process void Process ( TagHelperContext context , TagHelperOutput output ) Renders a \u003Ctime\u003E element with the UTC timestamp in the datetime attribute and data attributes for client-side JavaScript formatting. Parameters context Contains information associated with the current HTML tag. output A stateful HTML element used to generate an HTML tag. Exceptions ArgumentException Thrown when Value is the default value or if Display or Format have invalid values. Property RwType string? RwType { get; set; } Gets or sets the timezone type for RazorWire time formatting. Valid values: local (user\u0027s browser timezone) or utc (UTC timezone). Property Value DateTimeOffset Value { get; set; } The UTC timestamp to display, sourced from the datetime attribute. Property Display string Display { get; set; } Gets or sets the display mode for the formatted time. Valid values: time (default), date , datetime , or relative . Property Format string? Format { get; set; } Gets or sets the format style for absolute time formatting. Valid values: short , medium (default), long , or full .","snippet":"Type AutoAssetVersioningTagHelper A TagHelper that automatically applies version hashing to script and link tags that reference local files, if the asp-append-version attribute is missing. Method IsLocal bool IsLocal...","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-AutoAssetVersioningTagHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-AutoAssetVersioningTagHelper","title":"AutoAssetVersioningTagHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers","AutoAssetVersioningTagHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers#ForgeTrust-RazorWire-TagHelpers-AutoAssetVersioningTagHelper"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-IslandTagHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-IslandTagHelper","title":"IslandTagHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers","IslandTagHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers#ForgeTrust-RazorWire-TagHelpers-IslandTagHelper"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-LocalTimeTagHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-LocalTimeTagHelper","title":"LocalTimeTagHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers","LocalTimeTagHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers#ForgeTrust-RazorWire-TagHelpers-LocalTimeTagHelper"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-RazorWireFormTagHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-RazorWireFormTagHelper","title":"RazorWireFormTagHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers","RazorWireFormTagHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers#ForgeTrust-RazorWire-TagHelpers-RazorWireFormTagHelper"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-RazorWireScriptsTagHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-RazorWireScriptsTagHelper","title":"RazorWireScriptsTagHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers","RazorWireScriptsTagHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers#ForgeTrust-RazorWire-TagHelpers-RazorWireScriptsTagHelper"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-RequiresStreamTagHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-RequiresStreamTagHelper","title":"RequiresStreamTagHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers","RequiresStreamTagHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers#ForgeTrust-RazorWire-TagHelpers-RequiresStreamTagHelper"},{"id":"Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-StreamSourceTagHelper","path":"/docs/Namespaces/ForgeTrust.RazorWire.TagHelpers.html#ForgeTrust-RazorWire-TagHelpers-StreamSourceTagHelper","title":"StreamSourceTagHelper","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"RazorWire","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","ForgeTrust","RazorWire","TagHelpers","StreamSourceTagHelper"],"sourcePath":"Namespaces/ForgeTrust.RazorWire.TagHelpers#ForgeTrust-RazorWire-TagHelpers-StreamSourceTagHelper"},{"id":"Namespaces/Global.html","path":"/docs/Namespaces/Global.html","title":"Global","summary":"Type Program Process entry point for the AppSurface CLI executable. Remarks ProgramEntryPoint owns the command runtime seam and is covered by tests; this type only adapts the .NET process entry point to that seam.","headings":["Program"],"bodyText":"Type Program Process entry point for the AppSurface CLI executable. Remarks ProgramEntryPoint owns the command runtime seam and is covered by tests; this type only adapts the .NET process entry point to that seam.","snippet":"Type Program Process entry point for the AppSurface CLI executable. Remarks ProgramEntryPoint owns the command runtime seam and is covered by tests; this type only adapts the .NET process entry point to that seam.","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Global","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","Global"],"sourcePath":"Namespaces/Global"},{"id":"Namespaces/Global.html#Program","path":"/docs/Namespaces/Global.html#Program","title":"Program","summary":"","headings":[],"bodyText":"","snippet":"","pageType":"api-reference","pageTypeLabel":"API Reference","pageTypeVariant":"api-reference","audience":"developer","component":"Global","aliases":[],"keywords":[],"status":null,"navGroup":"API Reference","publicSection":"api-reference","publicSectionLabel":"API Reference","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Namespaces","Global","Program"],"sourcePath":"Namespaces/Global#Program"},{"id":"packages","path":"/docs/packages","title":"AppSurface v0.1 package chooser","summary":"Start with the package that matches the app you are building, then add optional web modules and support surfaces only when you need them.","headings":["Web app","Also building...","Package matrix","Support and proof-host surfaces","Support and runtime packages","Docs and proof hosts","Not in the direct-install matrix","Maintainer notes"],"bodyText":"AppSurface v0.1 package chooser Generated from packages/package-index.yml and evaluated project metadata. Do not edit this file by hand. AppSurface v0.1 is a coordinated .NET 10 package family. Start with the package that matches the app you\u0027re building, then add optional modules only when your app needs them. All direct-install packages and tools currently target net10.0 . Library package rows use dotnet package add ; in .NET 10, dotnet package add and dotnet add package are equivalent. Tool rows use dotnet tool install . Web app Install this first for a normal ASP.NET Core app with AppSurface modules when you want the base web startup pipeline before layering on optional UI or docs packages. Bash dotnet package add ForgeTrust.AppSurface.Web What you get: Base ASP.NET Core hosting, middleware and endpoint composition, conventional browser error-page hooks, and the core AppSurface web module contract. Not included: OpenAPI generation, Scalar UI, RazorWire reactive UI, Tailwind build integration, or the RazorDocs host. Read next: examples/web-app/README.md Release and readiness: Release hub keeps the public release story, adoption risk, and policy links in one place. Unreleased proof artifact shows what is queued for the next coordinated version. CHANGELOG.md is the compact ledger for tagged and in-flight package changes. Pre-1.0 upgrade policy explains the current stability contract before v1.0.0 . Also building... Start with ForgeTrust.AppSurface.Console for CLI commands or worker-style processes that should share AppSurface module composition. Add ForgeTrust.AppSurface.Dependency.Autofac when your app already uses Autofac and your modules need Autofac-specific registrations. Start with ForgeTrust.AppSurface.Aspire for distributed app-model projects and service-default composition. Add ForgeTrust.AppSurface.Web.Scalar after ForgeTrust.AppSurface.Web.OpenApi when you want a hosted API reference UI. Add ForgeTrust.RazorWire when you want reactive Razor UI, Turbo-style streams, and server-rendered islands. Add ForgeTrust.AppSurface.Web.Tailwind when you want Tailwind without a separate Node.js asset pipeline. Package matrix Swipe to compare package details on narrow screens. Package Use when Install Includes Does not include Start here Release ForgeTrust.AppSurface.Core Install this directly only when you are authoring reusable AppSurface modules or host integrations instead of starting from a web, console, or Aspire package. dotnet package add ForgeTrust.AppSurface.Core Core module abstractions, dependency graph orchestration, AppSurfaceStartup, and StartupContext. ASP.NET Core hosting, CliFx command hosting, Aspire app-model helpers, or optional integrations. Package README public preview commercial ready notes ForgeTrust.AppSurface.Config Add this when your AppSurface modules need strongly typed configuration primitives instead of ad hoc configuration lookups. dotnet package add ForgeTrust.AppSurface.Config AppSurfaceConfigModule, typed config objects, configuration providers, source-aware audit reports, and explicit configuration access patterns. Web hosting, UI docs, caching, or a separate secret-management system. Package README public preview commercial ready notes ForgeTrust.AppSurface.Caching Add this when your modules need lightweight in-process memoization and cache policy primitives. dotnet package add ForgeTrust.AppSurface.Caching AppSurfaceCachingModule, IMemo or Memo helpers, and cache policy primitives on top of Microsoft.Extensions.Caching.Memory. Distributed caching infrastructure, web hosting, or configuration binding. Package README public preview commercial ready notes ForgeTrust.AppSurface.Console Start here for CLI apps and worker-style entry points that should run through the AppSurface startup pipeline with CliFx. dotnet package add ForgeTrust.AppSurface.Console ConsoleStartup, ConsoleApp, hosted command execution, and CliFx command discovery through AppSurface modules. ASP.NET Core hosting, OpenAPI surfaces, or Razor-based UI composition. Package README public preview commercial ready notes ForgeTrust.AppSurface.Dependency.Autofac Add this when you need Autofac-specific registrations or container features instead of the default .NET service collection. dotnet package add ForgeTrust.AppSurface.Dependency.Autofac AppSurfaceAutofacModule and Autofac-aware service registration hooks for AppSurface modules. The default Microsoft DI container, web hosting, or command hosting by itself. Package README public preview commercial ready notes ForgeTrust.AppSurface.Aspire Start here for .NET Aspire app-model projects that want AppSurface-style modular composition for service defaults and distributed resources. dotnet package add ForgeTrust.AppSurface.Aspire AspireApp entry points and modular registration for distributed application resources and service defaults. ASP.NET Core web hosting, Razor UI features, or the standalone docs host. Package README public preview commercial ready notes ForgeTrust.AppSurface.Web Install this first for a normal ASP.NET Core app with AppSurface modules when you want the base web startup pipeline before layering on optional UI or docs packages. dotnet package add ForgeTrust.AppSurface.Web Base ASP.NET Core hosting, middleware and endpoint composition, conventional browser error-page hooks, and the core AppSurface web module contract. OpenAPI generation, Scalar UI, RazorWire reactive UI, Tailwind build integration, or the RazorDocs host. Package README public preview commercial ready notes ForgeTrust.AppSurface.Web.OpenApi Add this after the base web package when you want generated OpenAPI endpoints for an AppSurface web app. dotnet package add ForgeTrust.AppSurface.Web.OpenApi AddOpenApi wiring, endpoint explorer setup, endpoint mapping, and default OpenAPI document transforms. A hosted API reference UI or reactive Razor components. Package README public preview commercial ready notes ForgeTrust.AppSurface.Web.Scalar Add this after OpenAPI when you want Scalar\u0027s interactive API reference UI served by your AppSurface web app. dotnet package add ForgeTrust.AppSurface.Web.Scalar Scalar UI endpoint mapping and the OpenAPI module dependency needed to feed it. OpenAPI authoring by itself without the base web host, or reactive Razor component streaming. Package README public preview commercial ready notes ForgeTrust.RazorWire Add this when you want reactive Razor fragments, Turbo-style page updates, server-sent streams, or islands without moving to a separate frontend app. dotnet package add ForgeTrust.RazorWire RazorWire modules, TagHelpers, stream helpers, Razor fragment updates, and hybrid island support. OpenAPI generation, API reference UI, or Tailwind asset compilation. Package README public preview commercial ready notes ForgeTrust.AppSurface.Web.Tailwind Add this when you want Tailwind build and watch integration in an AppSurface web app without carrying a Node.js asset pipeline. dotnet package add ForgeTrust.AppSurface.Web.Tailwind Tailwind standalone CLI integration, watch mode, generated CSS output, and transitive runtime package selection for supported build hosts. JavaScript plugin ecosystems that require npm-first tooling, or direct runtime-package selection. Package README public preview commercial ready notes Support and proof-host surfaces Support and runtime packages ForgeTrust.AppSurface.Web.Tailwind.Runtime.linux-arm64 : Tailwind standalone runtime for Linux Arm64 build hosts. Restore it transitively through ForgeTrust.AppSurface.Web.Tailwind instead of installing it directly. Release: support runtime; not applicable; notes . ForgeTrust.AppSurface.Web.Tailwind.Runtime.linux-x64 : Tailwind standalone runtime for Linux x64 build hosts. Restore it transitively through ForgeTrust.AppSurface.Web.Tailwind instead of installing it directly. Release: support runtime; not applicable; notes . ForgeTrust.AppSurface.Web.Tailwind.Runtime.osx-arm64 : Tailwind standalone runtime for macOS Arm64 build hosts. Restore it transitively through ForgeTrust.AppSurface.Web.Tailwind instead of installing it directly. Release: support runtime; not applicable; notes . ForgeTrust.AppSurface.Web.Tailwind.Runtime.osx-x64 : Tailwind standalone runtime for macOS x64 build hosts. Restore it transitively through ForgeTrust.AppSurface.Web.Tailwind instead of installing it directly. Release: support runtime; not applicable; notes . ForgeTrust.AppSurface.Web.Tailwind.Runtime.win-x64 : Tailwind standalone runtime for Windows x64 build hosts. Restore it transitively through ForgeTrust.AppSurface.Web.Tailwind instead of installing it directly. Release: support runtime; not applicable; notes . Docs and proof hosts ForgeTrust.AppSurface.Docs : Reusable docs package for harvesting repository docs into a RazorDocs UI. This is a real package, but it is a proof-host surface rather than the default first install for general AppSurface apps. Release: proof host; not applicable; notes . Start here: RazorDocs README ForgeTrust.AppSurface.Docs.Standalone : Thin export host for serving or exporting RazorDocs. Treat it as a proof host and example app, not a package you install into another project. Release: proof host; not applicable; notes . Start here: Standalone host README Not in the direct-install matrix ForgeTrust.AppSurface.Cli : Planned public appsurface .NET tool. The docs verb owns RazorDocs preview workflows that were previously sketched as a separate razordocs CLI. Release: excluded; not applicable; notes . ForgeTrust.RazorWire.Cli : Held out of the direct-install chooser until issue #171 lands real .NET tool packaging and stable install guidance. Release: excluded; not applicable; notes . Maintainer notes Edit packages/package-index.yml when the public package story changes. Keep publish_decision and expected_dependency_package_ids in packages/package-index.yml aligned with the package artifact workflow so the chooser and release contract share one package source of truth. Run dotnet run --project tools/ForgeTrust.AppSurface.PackageIndex/ForgeTrust.AppSurface.PackageIndex.csproj -- generate after changing package classifications or package READMEs. Run dotnet run --project tools/ForgeTrust.AppSurface.PackageIndex/ForgeTrust.AppSurface.PackageIndex.csproj -- verify-packages --package-version 0.0.0-ci.local before publishing changes that affect package metadata, project references, or Tailwind runtime payloads. Run dotnet run --project tools/ForgeTrust.AppSurface.PackageIndex/ForgeTrust.AppSurface.PackageIndex.csproj -- gate before publishing rebrand or release metadata changes. Keep packages/README.md.yml hand-authored so RazorDocs metadata, trust-bar copy, and section placement stay intentional.","snippet":"AppSurface v0.1 package chooser Generated from packages/package-index.yml and evaluated project metadata. Do not edit this file by hand. AppSurface v0.1 is a coordinated .NET 10 package family. Start with the package...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Start Here","publicSection":"start-here","publicSectionLabel":"Start Here","isSectionLanding":false,"order":50,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Start Here","Packages"],"sourcePath":"packages/README.md"},{"id":"releases","path":"/docs/releases","title":"Releases","summary":"Start with the public release hub, then drill into the unreleased proof artifact, the compact changelog, and the pre-1.0 upgrade policy.","headings":["Start here","Release format","Story first","Safety second","Archive third","What belongs in the release surface","What does not belong in public release notes"],"bodyText":"Release notes and change management AppSurface now treats release notes as a product surface instead of a post-ship afterthought. This folder is the public record that answers three questions quickly: What is changing next? How risky is it to adopt? Where will the final tagged story live once a version ships? It also acts as a concrete RazorDocs example for teams that want stronger release notes in their own products. Start here Package chooser is the fastest install map for deciding which AppSurface package to add first. Unreleased is the living proof artifact for the next coordinated AppSurface version. Changelog is the compact ledger that points to unreleased and tagged stories. Pre-1.0 upgrade policy explains the stability contract before v1.0.0 . Release authoring checklist is the maintainer workflow for turning the unreleased page into a tagged release. Release format Story first Each release note should open with the narrative that matters to evaluators and adopters. Explain what changed, why it matters, and which parts of the product surface are affected before dropping into mechanical lists. Safety second Every release note should make upgrade risk obvious near the top. Call out whether the note is unreleased or tagged, which surfaces are affected, how fresh the information is, and where migration guidance lives. Archive third Once AppSurface starts cutting tags, the long-form release note will live in this folder and the compact summary will live in CHANGELOG.md . Tagged notes become the durable archive for migration details and release narrative. What belongs in the release surface Package behavior changes CLI behavior changes Docs-facing behavior changes that affect adopters or evaluators Example changes that alter the recommended path Release policy changes What does not belong in public release notes Private maintainer-only recovery steps, secret handling, and operational escape hatches should live outside harvested docs. In this repository, those notes belong under .github/ .","snippet":"Release notes and change management AppSurface now treats release notes as a product surface instead of a post-ship afterthought. This folder is the public record that answers three questions quickly: What is changing...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Releases","publicSection":"releases","publicSectionLabel":"Releases","isSectionLanding":false,"order":10,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Releases"],"sourcePath":"releases/README.md"},{"id":"releases/release-authoring-checklist","path":"/docs/releases/release-authoring-checklist","title":"Release authoring checklist","summary":"Maintainer workflow for turning the unreleased proof artifact into a tagged release note.","headings":["Before the release branch or tag","When cutting the tagged release note","After the tag ships"],"bodyText":"Release authoring checklist Use this checklist when turning the living unreleased story into a tagged AppSurface release. Before the release branch or tag make sure the pull request queue has updated unreleased.md regroup the story so the opening narrative explains what changed and why it matters confirm every breaking or behavior-changing update has migration guidance update CHANGELOG.md so the compact ledger matches the narrative release note When cutting the tagged release note start from the tagged release template replace provisional language with tagged facts: version, date, shipped scope, and finalized migration steps keep the trust bar accurate for the release state and archive location link the tagged note from CHANGELOG.md After the tag ships trim unreleased.md back to the next in-flight version keep only still-unreleased items in the proof artifact verify the /docs release hub resolves to the new tagged note and current policy pages","snippet":"Release authoring checklist Use this checklist when turning the living unreleased story into a tagged AppSurface release. Before the release branch or tag make sure the pull request queue has updated unreleased.md...","pageType":"how-to","pageTypeLabel":"How-To","pageTypeVariant":"how-to","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Releases","publicSection":"releases","publicSectionLabel":"Releases","isSectionLanding":false,"order":40,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Releases","Release authoring checklist"],"sourcePath":"releases/release-authoring-checklist.md"},{"id":"releases/unreleased","path":"/docs/releases/unreleased","title":"Unreleased","summary":"Living proof artifact for the next coordinated AppSurface release. This page is intentionally provisional until a version is tagged.","headings":["What is taking shape","Included in the next coordinated version","Release and docs surface","Contribution contract","Console and CLI polish","Core diagnostics","Dependency maintenance","Configuration validation","Web host development defaults","RazorWire package guidance","RazorDocs product example","RazorWire form UX","Migration watch","Proof artifacts","Before the first tag"],"bodyText":"Unreleased This is the living release note for the next coordinated AppSurface version. It is intentionally written in the same blog-style shape we want future tagged releases to use, but everything here remains provisional until a tag is cut. What is taking shape AppSurface is putting the release contract in place before v0.1.0 . This slice is about making release notes auditable, public, and reusable: a root changelog that acts as the compact ledger a public unreleased proof artifact a pre-1.0 upgrade policy with a clear migration home a top-of-page trust bar for release notes and policy pages pull-request guards that keep PR titles and unreleased entries aligned with future release automation Included in the next coordinated version Release and docs surface The /docs landing now promotes a Releases entry point alongside product proof paths. AppSurface now ships a public release hub, a changelog, an unreleased page, and a tagged release template inside the repository. Release-note pages can show status, freshness, scope, migration guidance, and provenance in a shared trust bar instead of bespoke page chrome. AppSurface now ships a generated package chooser that tells first-time adopters which package to install first, which optional modules to add next, and which proof paths to follow for release risk and working examples. AppSurface now builds and uploads validated prerelease package artifacts on pull requests and manual workflow runs, using the package chooser manifest as the single source of truth for publish decisions, dependency expectations, tool packages, first-party DLL version identity, and Tailwind runtime payload presence before NuGet publishing is enabled. AppSurface now has a protected, tag-only NuGet prerelease publish workflow that revalidates package artifact manifests, force-fetches the pushed annotated tag before validation, uses NuGet Trusted Publishing instead of a long-lived API key, requires a reviewed nuget-prerelease environment, writes a redacted publish ledger, and smoke-restores published packages from a clean NuGet configuration before a prerelease is considered ready. The public docs Start Here path now leads with an AppSurface evaluator sequence for teams comparing module-based startup against plain ASP.NET Core Program.cs configuration. The root README now has a single hello-world quickstart that starts the smallest web example on an explicit port and proves the response with curl . Contribution contract Pull request titles are now expected to follow Conventional Commits so the merge history is machine-readable for future automation. Pull requests are expected to update this page unless maintainers explicitly mark the change as outside the public release story. The primary build workflow now declares explicit read-only GITHUB_TOKEN contents permissions, keeping CI aligned with least-privilege GitHub Actions defaults. Markdown-only changes on main now republish the docs surface, so release-note and policy edits are treated as first-class product updates. AppSurface now exposes focused GitHub issue forms for bug reports, feature requests, and docs/developer-experience feedback, with the root README and contribution guide pointing developers to that feedback path. Public contribution surfaces now steer suspected vulnerabilities away from issue forms and into a private security reporting path. GitHub issue template support links now point first-time adopters to the package chooser and release/upgrade contract when they are evaluating install path or migration risk. Console and CLI polish AppSurface console apps can now opt into a command-first output contract so public CLI help and validation flows stay quiet instead of printing Generic Host lifecycle chatter. AppSurface now plans two public CLI tools: appsurface for repository-level AppSurface workflows, starting with appsurface docs for RazorDocs preview, and razorwire for RazorWire-specific export workflows. RazorWire CLI now uses that contract for --help , export --help , invalid option output, and missing-source validation while still preserving command-owned export progress logs. RazorWire CLI now names export seed-route files with -r|--seeds , matching the seed terminology used throughout the exporter and docs. The shared console startup seam now exposes ConsoleOptions and ConsoleOutputMode , so future public AppSurface CLIs can adopt the same behavior without forking startup logic. RazorWire CLI now has a first-class .NET tool package contract with the razorwire command, supports exact-version dnx execution from published or explicit local package sources, and verifies the installed tool path through help and sample export smoke tests. Public package publishing remains manual until the coordinated release automation tracked in #161 lands. RazorWire CLI export now defaults to CDN-safe static output. Managed internal URLs discovered in HTML and CSS are rewritten to emitted artifacts, \u003Cimg\u003E and \u003Csource\u003E srcset candidates are both covered, RazorDocs frame content emits static partials, conventional 404.html participates in the same validation, and CDN validation fails with RWEXPORT### diagnostics when required frame or asset dependencies cannot become files. Project exports now disable persistent MSBuild build servers during CLI-controlled publish and assembly-name probes so captured tool output cannot hang on reused build nodes. RazorWire CLI process cleanup now waits for asynchronous stdout and stderr callbacks to flush before disposing launched target processes, which keeps short-lived command output observable in tests and diagnostics. RazorWire CLI validation errors now include a concrete source-selection example and razorwire export --help hint, so a failed export tells developers the next useful command instead of only naming the bad input. RazorWire CLI users who still want extensionless, server-routed export output should pass --mode hybrid . The default cdn mode is for plain static hosts and CDNs, not S3-specific infrastructure. PackageIndex now has a real --help / -h surface that exits successfully, describes its commands and options, and reports unknown commands before printing usage. Core diagnostics Core static utilities now use explicit ILogger overloads and source-generated [LoggerMessage] definitions for host-owned diagnostics. PathUtils.FindRepositoryRoot can warn when discovery falls back from a missing path, and parallel enumerable cleanup paths now log suppressed cleanup failures at Debug when a caller supplies a logger. Dependency maintenance The centrally managed YamlDotNet dependency now targets 17.0.1 , and the affected PackageIndex, RazorDocs, and Aspire lock files have been regenerated. The Autofac dependency package now has dedicated test coverage for AppSurface module integration, host container setup, dependent module loading, and implementation scanning. Configuration validation Strongly typed config wrappers now validate resolved object values with DataAnnotations during startup, including defaults, and report operator-friendly ConfigurationValidationException failures without echoing attempted values. Configuration audits can now produce a source-aware report for discovered wrappers and explicitly registered keys, showing provider order, file and environment provenance, defaults, validation diagnostics, and redacted display-safe values. Nested config validation can now opt into Microsoft Options [ValidateObjectMembers] and [ValidateEnumeratedItems] markers while AppSurface owns traversal, path formatting, and cycle protection. Scalar config wrappers can now validate resolved primitive values directly with ConfigValueNotEmpty , ConfigValueRange , and ConfigValueMinLength attributes, while wrapper-specific scalar rules can override ValidateValue . Config wrappers can now opt into required resolved presence with ConfigKeyRequired , so startup fails when no provider value and no default are available while defaults and supplied zero values still count as present. ConfigKeyAttribute now lives in its own public API source file, keeping configuration key attributes discoverable while leaving AppSurfaceConfigModule focused on service registration. The new examples/config-validation sample demonstrates an intentional startup validation failure for a scalar ConfigStruct\u003Cint\u003E without printing the invalid configured value. Environment variables can now patch individual members of object-valued config loaded from lower-priority providers, so APP__SETTINGS__DATABASE__PORT can override one nested value without replacing the rest of the JSON-backed options object. Web host development defaults AppSurface web hosts now choose a deterministic localhost-only development URL when no endpoint is configured, while production, staging, container, and appsettings-based endpoint choices remain untouched. AppSurface web hosts now fail fast when startup does not complete before WebOptions.StartupTimeout , which defaults to 30 seconds and catches pre-bind stalls from sandbox restrictions, package layout issues, static asset discovery, or hosted services that block startup. OpenAPI\u0027s optional web package now has dedicated test coverage for service registration, endpoint mapping, generated document titles, and transformer behavior that removes ForgeTrust.AppSurface.Web tags at the document and operation levels while preserving unrelated tags, so the public module contract is guarded independently of Scalar. Scalar\u0027s optional web package now has dedicated test coverage for OpenAPI dependency wiring, Scalar endpoint mapping, no-op lifecycle hooks, and minimal AppSurface web host composition. Tailwind development watch mode now treats a missing standalone CLI as a recoverable local-tooling gap: the app keeps serving existing CSS and logs a warning that points to the runtime package or TailwindCliPath override. AppSurface\u0027s conventional browser 404 page now prioritizes user recovery paths, including documentation search for missing /docs/... routes and a home link for other misses, while still documenting how app owners can override the default page. AppSurface Web now ships conventional browser status pages for empty HTML 401 , 403 , and 404 responses. The public surface is now BrowserStatusPageMode , BrowserStatusPageModel , UseConventionalBrowserStatusPages() , and DisableBrowserStatusPages() , with preview routes at /_appsurface/errors/401 , /_appsurface/errors/403 , and /_appsurface/errors/404 . Browser status page overrides are status-specific: use ~/Views/Shared/401.cshtml , ~/Views/Shared/403.cshtml , or ~/Views/Shared/404.cshtml . JSON/API responses, non-empty responses, and non-GET/HEAD requests keep their original behavior. Static export remains deliberately 404-only. RazorWire CLI probes /_appsurface/errors/404 and writes 404.html ; it does not emit 401.html or 403.html . AppSurface Web can now opt into a conventional production 500 page backed by ASP.NET Core exception handling, rendering only safe generic copy and a request id while leaving Development exception diagnostics and API-oriented responses alone. AppSurface now assigns explicit numeric values to public Web and RazorWire enums, preserving existing ordinals for consumers that persist, serialize, bind, or compare those values. AppSurface startup now keeps custom StartupContext.ApplicationName values as display labels while preserving assembly-backed host identity for ASP.NET static web asset manifests, so custom-labeled web hosts can still serve package styles and scripts. RazorWire package guidance RazorWire now has a generated UI design contract for package-owned nodes. The contract separates RazorWire UI from app-authored markup and RazorDocs chrome, establishes data-rw-* attributes plus --rw-ui-* custom properties as the default styling surface, and documents global, form-level, and target-level override expectations for future generated UI. RazorWire README snippets are now source-backed by the MVC sample through a MarkdownSnippets generator, with CI verification and README contract tests guarding quickstart drift. RazorDocs product example AppSurface\u0027s own release pages now double as a working RazorDocs example for consumers who want better release notes. RazorDocs now supports a static-first versioned docs surface: /docs can point at the recommended released tree, /docs/next can stay on the live preview, /docs/v/{version} can serve exact historical releases, and /docs/versions can act as the public archive. RazorDocs route families can now be mounted away from /docs with RazorDocs:Routing:RouteRootPath , so consumers can host docs under paths such as /foo/bar while archive, exact-version, search, metadata, and static export URLs stay aligned. RazorDocs now registers only its configured docs routes instead of an app-wide controller/action fallback, keeping docs routing isolated from other modules. Published RazorDocs release trees are now catalog-driven and validated before they are mounted, so broken historical exports stay unavailable instead of half-rendering with cross-version search or asset leakage. RazorDocs pages can now expose typed On this page outlines, explicit proof-path previous/next links, related-page cards, and sidebar anchor navigation from harvested metadata instead of scraping rendered HTML. RazorDocs details pages now render those On this page outlines as a page-local navigation surface, using a sticky desktop rail, a compact narrow-viewport drawer, and active-section state that keeps the reader oriented without competing with the global sidebar. RazorDocs compact On this page outlines now stay visible while reading on narrow viewports, showing smaller previous/next context around the current section with reduced-motion-safe rolling label updates. RazorDocs compact On this page outlines now contain their own scrolling while expanded, preventing touch or wheel input over the outline from scrolling the article behind it. RazorDocs details pages now emit the outline client as a normal deferred script asset, so static exports publish /docs/outline-client.js through the existing asset crawler instead of depending on an inline loader. RazorDocs detail-page outlines now keep long-section active states and the desktop right rail aligned, including the full-height rail rule, active-item visibility on long pages, and animated section jumps. Public docs navigation now groups pages by intent-first sections, preserves authored editorial breadcrumbs, and keeps Start Here recovery links hidden when that section is unavailable. RazorDocs API Reference navigation now keeps the primary sidebar at package and namespace depth, nests deeper namespace pages under their nearest parent with leaf labels, and leaves generated type and member anchors to namespace-page outlines, source links, and search instead of expanding hundreds of symbols in the left rail. RazorDocs landing curation now uses featured_page_groups , so root and section landing pages can organize next-step links by reader intent instead of rendering one flat list. RazorDocs now exposes structured harvest health through DocAggregator.GetHarvestHealthAsync(...) , letting hosts distinguish healthy, valid-empty, degraded, and all-failed source-backed docs snapshots while keeping raw exception details in logs. RazorDocs hosts can now opt into strict startup failure with RazorDocs:Harvest:FailOnFailure , so CI, release, and static export runs fail before listening when every configured harvester fails while runtime hosts stay tolerant by default. RazorDocs and RazorWire now compile their package-owned runtime assets into their assemblies and map endpoint fallbacks for those assets. Static web assets remain the normal host path when manifests are available, while packaged CLI hosts can still serve the docs stylesheet, search scripts, outline script, and RazorWire runtime from compiled assemblies. RazorDocs now exposes a local-first harvest health UI at {DocsRootPath}/_health plus a machine-readable {DocsRootPath}/_health.json endpoint, shown by default in Development and configurable independently from sidebar chrome for operator-owned environments. RazorDocs page lookup now uses one shared path resolver for details pages, landing curation, related-page links, and search recovery links, keeping source paths, canonical .html paths, fragments, backslash normalization, and configured docs-root prefixes behaviorally aligned. RazorDocs authored Markdown pages now publish clean canonical routes that follow their public section hierarchy, so teams can link to URLs such as /docs/packages instead of repository-shaped README.md.html paths while source-path lookups and declared aliases continue to work. RazorDocs now permanently redirects public Markdown source-shaped requests such as /docs/packages/README.md to the clean canonical route, so links copied from GitHub or editor paths recover instead of falling into the generic 404 page. The release contract is designed so future tooling can generate both a changelog entry and a blog-style tagged release note from the same underlying signals. RazorDocs now rewrites authored doc links from a harvested target manifest instead of broad suffix heuristics, so normal site links such as ../privacy.html stay untouched and missing doc targets do not become broken /docs/... routes. RazorDocs details pages can now render a Source of truth strip with View source , Edit this page , and relative Last updated evidence driven by contributor metadata, configured URL templates, and git freshness when available. The primary RazorDocs Pages deployment now exports with contributor provenance configured and full git history available, so the public docs artifact can show the same Source of truth strip as local smoke tests. Contributor provenance now degrades safely: namespace and API pages stay explicit-override-only for the MVP, and missing or slow git history omits only freshness instead of breaking docs rendering. RazorDocs generated C# API references can now render per-symbol source links for documented types, methods, properties, and enums that point at the exact source file and line, with immutable refs available when hosts want links pinned to the code version used to build the docs. The primary RazorDocs Pages deployment now configures commit-pinned symbol source links, so generated C# API Source chips resolve to the exact file and line from the CI build revision. Pull requests now run the RazorDocs CDN static export during PR validation, while Pages artifact upload and deployment remain limited to main , so broken managed links are caught before the public docs pipeline reaches deployment. RazorWire CDN export now ignores authoring-only source-navigation anchors, including repo-relative links to common source and project files and app-rendered anchors marked with data-rw-export-ignore . RazorDocs snapshot caching is now configurable with RazorDocs:CacheExpirationMinutes , so development hosts can shorten reuse while production hosts can choose a longer docs and search-index cache lifetime. Shared RazorDocs badges, metadata chips, provenance strips, and trust bars now live in the shared package stylesheet while search.css stays focused on search-specific UI. RazorDocs shared package chrome and search UI now consume one internal --docs-* design-token layer, with search.css fallback aliases so exact published release trees keep styled search controls even when they load the search stylesheet without the generated package stylesheet. RazorDocs legacy asset redirects now validate app-relative redirect targets before preserving cache-busting query strings, closing an open-redirect path while keeping virtual-path deployments and packaged asset fallbacks working. RazorDocs authored Markdown pages now use a dedicated prose treatment with a shorter line length, stronger paragraph rhythm, readable lists, clearer links, blockquotes, and inline code while generated API pages keep the wider reference layout. RazorDocs fenced Markdown code blocks now render server-side syntax highlighting through TextMateSharp with RazorDocs-owned token classes, language badges, and escaped plaintext fallback when a language is unknown, unsupported, oversized, or cannot be tokenized safely. RazorDocs search now keeps failure recovery markup out of the active search shell until the index actually fails to load, so successful searches no longer expose hidden failure copy to text extraction tools. RazorDocs search now opens as a richer workspace with representative starter rows, filter-first browsing, stronger no-results recovery, and normalized release badge aliases. RazorDocs harvesting now excludes test-project docs and generated example-app API reference from the docs surface while keeping authored example README walkthroughs public. RazorDocs now includes a repository root LICENSE file as a docs artifact when present, so repo-relative license links remain revision-correct and still pass CDN static export validation. RazorDocs now documents the namespace README merge contract with positive and negative examples, while detail-page titles wrap on narrow screens so long package names do not clip on mobile. RazorDocs details pages now suppress duplicated leading Markdown H1s when the generated shell owns the page heading, including leading comment markers and merged namespace README intros. RazorDocs now has an authored consumer landing page for teams evaluating how to use RazorDocs in their own repositories, and the root docs landing features it through featured_page_groups instead of hardcoded controller copy. RazorDocs now treats Releases as a first-class public section and suppresses breadcrumb links to generated parent routes that do not correspond to published docs pages, keeping static export warnings focused on actionable broken links. RazorDocs wayfinding coverage now waits for docs content replacement before asserting sequence-link destinations, keeping the details-page proof path deterministic in CI. RazorDocs Playwright integration coverage now hosts the standalone docs app in-process through the standalone host builder, avoiding fixture-time dotnet run rebuilds and stale standalone bin output during focused test runs. RazorWire form UX RazorWire-enhanced forms now get a convention-based failed-submission stack: durable request markers, default form-local fallback UI, handled server validation helpers, and runtime events for custom consumers. Development anti-forgery failures from RazorWire forms now return useful diagnostics with safe production copy, so stale or missing token problems are easier to fix without exposing implementation detail to users. The MVC sample now includes /Reactivity/FormFailures , covering validation, anti-forgery, authorization, malformed request, server failure, default styling, CSS variable customization, and manual event-driven rendering. The MVC sample now persists its demo username cookie with Secure , HttpOnly , and SameSite=Lax , and its browser-level regression coverage runs through localhost so local development keeps the secure-cookie behavior observable. The MVC sample counter keeps its compact icon-only button while exposing an Increment counter accessible name for assistive technology and role-based tests. Migration watch There is no tagged migration guide yet because AppSurface has not cut v0.1.0 . Until then: breaking changes should be called out here as soon as they land the stable policy lives in Pre-1.0 upgrade policy finalized migration steps move into the tagged release note when the version ships custom RazorDocs harvesters that want detail-page outlines and search heading metadata should populate DocNode.Outline ; pages without outline metadata continue to render without the optional outline section RazorDocs hosts that need source-backed harvest status should use DocAggregator.GetHarvestHealthAsync(...) and branch on DocHarvestHealthStatus plus diagnostic codes. Empty snapshots are not failures, degraded snapshots may still serve partial docs, and hosts that publish release artifacts should enable RazorDocs:Harvest:FailOnFailure when all-failed snapshots must stop startup. DocAggregator.GetSearchIndexPayloadAsync(...) is no longer a supported package-consumer API. The live search-index payload is now treated as an internal RazorDocs implementation detail so the host can rebase docs paths and serialize once per request. Consumers that previously called that method directly should switch to the public docs search endpoint or build their own search payload contract instead of depending on RazorDocs\u0027 internal snapshot shape. existing rw-active forms opt into failed-form request markers and default fallback UI; applications with custom failure rendering can use RazorWireOptions.Forms.FailureMode = Manual , RazorWireOptions.Forms.EnableFailureUx = false , or per-form data-rw-form-failure=\u0022off\u0022 RazorDocs authors should migrate flat featured_pages metadata to featured_page_groups . The old field is ignored and logs a warning; each group needs at least label or intent , plus a pages list containing the existing question , path , supporting_copy , and order entries. Code that previously read IHostEnvironment.ApplicationName to recover a custom AppSurface display label should read StartupContext.ApplicationName instead. IHostEnvironment.ApplicationName now stays aligned with the host entry-assembly identity used for static web asset discovery unless StartupContext.OverrideEntryPointAssembly explicitly selects a different manifest identity. StartupContext.EntryPointAssembly still defaults to the root module assembly for command/controller/component discovery, so existing cross-assembly scanning behavior remains stable. Web apps with custom conventional 404 views should change @model ForgeTrust.AppSurface.Web.NotFoundPageModel to @model ForgeTrust.AppSurface.Web.BrowserStatusPageModel . The old 404-only options API names have moved to BrowserStatusPage* names before v0.1.0 ; conventional production 500 exception pages now ship as the opt-in fix for issue #224. Proof artifacts Release hub Changelog Pre-1.0 upgrade policy Release authoring checklist Before the first tag The current intent is that everything already in this repository can be part of v0.1.0 when AppSurface is ready to release. This page is where that pile becomes visible and reviewable before the tag exists.","snippet":"Unreleased This is the living release note for the next coordinated AppSurface version. It is intentionally written in the same blog-style shape we want future tagged releases to use, but everything here remains...","pageType":"release-note","pageTypeLabel":"Release","pageTypeVariant":"release","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Releases","publicSection":"releases","publicSectionLabel":"Releases","isSectionLanding":false,"order":15,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Releases","Unreleased"],"sourcePath":"releases/unreleased.md"},{"id":"releases/upgrade-policy","path":"/docs/releases/upgrade-policy","title":"Pre-1.0 upgrade policy","summary":"Stability and migration contract for AppSurface before the first tagged release.","headings":["Core policy","Where migration notes live","What counts as a release-note-worthy change","What does not count as a migration note by itself","Expectations before v0.1.0"],"bodyText":"Pre-1.0 upgrade policy AppSurface is still before v1.0.0 , so rapid change is expected. That does not mean changes should be surprising. This policy explains how AppSurface will talk about risk and where migration guidance belongs before the first stable release. Core policy AppSurface releases the monorepo in unison. One version applies to the whole repository. Breaking and behavior-changing updates are allowed before v1.0.0 , but they must be called out in the public release surface. Migration guidance must have a durable home. The short form belongs in CHANGELOG.md , and the detailed walkthrough belongs in the matching release note. Where migration notes live Before a version is tagged: put provisional guidance in unreleased.md . When a version is tagged: move the finalized guidance into the versioned release note under releases/ . Keep CHANGELOG.md concise and link readers to the full release note when more detail is needed. What counts as a release-note-worthy change API changes that alter signatures, defaults, ordering requirements, or expected lifecycle behavior CLI changes that alter commands, flags, defaults, or output that users depend on Example changes that replace the recommended way to compose AppSurface Docs-facing behavior changes that affect how consumers discover, configure, or trust the product What does not count as a migration note by itself private maintainer-only recovery notes secret or credential handling details repo maintenance that does not affect adopters Those belong outside harvested public docs. Expectations before v0.1.0 Prefer documenting a breaking change the same day it lands. If a change is large enough to require choreography, add explicit step-by-step guidance to the unreleased note. Do not hide pre-1.0 instability. Make it legible.","snippet":"Pre-1.0 upgrade policy AppSurface is still before v1.0.0 , so rapid change is expected. That does not mean changes should be surprising. This policy explains how AppSurface will talk about risk and where migration...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Releases","publicSection":"releases","publicSectionLabel":"Releases","isSectionLanding":false,"order":30,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["Releases","Pre-1.0 upgrade policy"],"sourcePath":"releases/upgrade-policy.md"},{"id":"security","path":"/docs/security","title":"Security Policy","summary":"AppSurface is pre-\u0060v1.0.0\u0060, but security reports still need a private path.","headings":["Reporting a vulnerability","What to include","Public issue forms"],"bodyText":"Security Policy AppSurface is pre- v1.0.0 , but security reports still need a private path. Reporting a vulnerability Do not open a public GitHub issue for suspected vulnerabilities, leaked secrets, exploit details, or reports that include sensitive deployment information. Use GitHub\u0027s private security advisory flow instead: report a vulnerability privately . If GitHub does not show the private reporting form for your account, open a public issue titled security contact request with no vulnerability details and ask a maintainer for a private disclosure channel. Include only non-sensitive routing context, such as the affected package name, when that information is safe to share publicly. What to include The affected package, example, tool, or documentation surface. The smallest reproduction you can safely share. The potential impact and any known preconditions. Whether the issue is already public or actively exploited. Public issue forms The bug and docs/developer-experience issue forms are for non-sensitive reports only. Maintainers may move public issues into a private disclosure flow if a report contains security-sensitive details.","snippet":"Security Policy AppSurface is pre- v1.0.0 , but security reports still need a private path. Reporting a vulnerability Do not open a public GitHub issue for suspected vulnerabilities, leaked secrets, exploit details,...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","Security Policy"],"sourcePath":"SECURITY.md"},{"id":"start-here/appsurface-evaluator","path":"/docs/start-here/appsurface-evaluator","title":"Start Here for AppSurface Evaluators","summary":"Follow the shortest path for deciding whether AppSurface fits an ASP.NET Core app or a team-wide startup standard.","headings":["The Short Path","What AppSurface Is","What To Look For","Common Pitfalls"],"bodyText":"Start Here for AppSurface Evaluators Use this path when you need to decide whether AppSurface belongs in an ASP.NET Core service or across a set of services. The target reader is a team lead, engineering manager, architect, or senior developer who owns startup consistency. You may be evaluating from one service first. That is fine. The question is still the same: when does a named AppSurface module make startup clearer than keeping the setup directly in Program.cs ? The Short Path Read Should I Use AppSurface? to decide whether plain ASP.NET Core is still enough. Run First Success Path to prove the smallest web app starts. Read From Program.cs to an AppSurface Module to inspect one concrete startup concern as a module. Keep Troubleshoot Startup and Modules nearby if the first run or module composition does not behave as expected. Use the AppSurface Glossary when a term in package docs is unfamiliar. What AppSurface Is AppSurface is a small module composition layer over familiar .NET and ASP.NET Core primitives. It does not replace the host, middleware, routing, dependency injection, or options model. AppSurface gives you a place to name startup concerns. A module can register services, configure host behavior, configure web options, register middleware, and map endpoints through one documented surface. Start with the package chooser when you need an install path. Start with this evaluator path when you need the adoption argument. What To Look For Look for a setup concern that is repeated, safety-sensitive, or easy to configure differently in each service. Good early candidates look like this: Each service needs the same browser-facing recovery behavior. Each service needs the same API-friendly exception or status behavior. A team wants the same startup convention without copying a block of Program.cs . A setup concern has enough policy that it deserves a name, tests, and reference docs. AppSurface is not valuable because Program.cs is bad. It is valuable when Program.cs is carrying a policy that your team should understand, reuse, and verify. Common Pitfalls Do not install every optional AppSurface package first. Pick the package that matches the app. Do not hide ASP.NET Core. AppSurface should make the underlying ASP.NET Core behavior easier to find, not harder. Do not turn a one-off local choice into a shared module too early. Name the concern when the policy matters. Do not compare AppSurface against large application frameworks in this Start Here path. The first comparison is plain ASP.NET Core startup code.","snippet":"Start Here for AppSurface Evaluators Use this path when you need to decide whether AppSurface belongs in an ASP.NET Core service or across a set of services. The target reader is a team lead, engineering manager,...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":["AppSurface evaluator","team standard","startup standardization","plain ASP.NET Core"],"keywords":["Program.cs","modules","startup","team lead","architect"],"status":null,"navGroup":"Start Here","publicSection":"start-here","publicSectionLabel":"Start Here","isSectionLanding":true,"order":10,"sequenceKey":"appsurface-evaluator","canonicalSlug":null,"relatedPages":["start-here/should-i-use-appsurface.md","start-here/first-success-path.md","packages/README.md"],"breadcrumbs":["Start Here","Start Here for AppSurface Evaluators"],"sourcePath":"start-here/appsurface-evaluator.md"},{"id":"start-here/first-success-path","path":"/docs/start-here/first-success-path","title":"First Success Path","summary":"Run the existing minimal web example and verify the first response before reading deeper docs.","headings":["What This Example Shows","What This Example Does Not Prove","Pitfalls"],"bodyText":"First Success Path Run the smallest web example first. Do not install optional packages yet. From the repository root: Bash dotnet run --project examples/web-app -- --port 5055 Then open http://127.0.0.1:5055 or run: Bash curl http://127.0.0.1:5055 Expected response: Plain text Hello World from the root! That proves the base ForgeTrust.AppSurface.Web path: a root module, the AppSurface startup pipeline, and one mapped endpoint. What This Example Shows The example uses WebApp\u003CExampleModule\u003E.RunAsync(...) and maps the root endpoint from web options. The module also contributes its own endpoint at /module . Try it: Bash curl http://127.0.0.1:5055/module Expected response: Plain text Hello from the example module! What This Example Does Not Prove This first run does not prove the status-page behavior used later in the evaluator path. It only proves the base web host starts and the module contributes behavior. For the status-page proof, read From Program.cs to an AppSurface Module . That page points at the Web package behavior and the tests that verify browser status pages and production exception pages. Pitfalls Pass --port 5055 when following docs. Without it, AppSurface may choose a deterministic development port for your worktree. Start with ForgeTrust.AppSurface.Web for a normal web app. Add optional modules only when the package chooser points to them. Treat the startup log as the source of truth if you choose a different port. Next: From Program.cs to an AppSurface Module","snippet":"First Success Path Run the smallest web example first. Do not install optional packages yet. From the repository root: Bash dotnet run --project examples/web-app -- --port 5055 Then open http://127.0.0.1:5055 or run:...","pageType":"tutorial","pageTypeLabel":"Tutorial","pageTypeVariant":"neutral","audience":null,"component":null,"aliases":["quickstart","first run","hello world"],"keywords":["WebApp","root module","dotnet run","examples/web-app"],"status":null,"navGroup":"Start Here","publicSection":"start-here","publicSectionLabel":"Start Here","isSectionLanding":false,"order":30,"sequenceKey":"appsurface-evaluator","canonicalSlug":null,"relatedPages":["examples/web-app/README.md","Web/ForgeTrust.AppSurface.Web/README.md","guides/from-program-cs-to-module.md"],"breadcrumbs":["Start Here","First Success Path"],"sourcePath":"start-here/first-success-path.md"},{"id":"start-here/should-i-use-appsurface","path":"/docs/start-here/should-i-use-appsurface","title":"Should I Use AppSurface?","summary":"Decide when plain ASP.NET Core startup code is enough and when an AppSurface module makes a setup concern clearer.","headings":["Decision Matrix","Use Plain ASP.NET Core When","Use AppSurface When","Pitfalls"],"bodyText":"Should I Use AppSurface? Start with plain ASP.NET Core. Reach for AppSurface when a startup concern is important enough to name, test, document, and reuse. That rule works for one service and for many services. A single Program.cs can still benefit when the setup is complex, safety-sensitive, or easy to get wrong. The value becomes more obvious when the same concern appears across several services. Decision Matrix Situation Plain ASP.NET Core is enough AppSurface helps One small service has a simple startup file Keep the code in Program.cs . Not needed yet. One service has setup policy that is hard to read or easy to misorder Still possible, especially with local extension methods. Name the policy as a module and test the behavior. Several services copy the same startup block Works, but drift is likely. Put the shared convention behind one module contract. A team needs onboarding docs for startup behavior The docs must explain local code in each app. The docs can point to one module and its behavior contract. The app needs custom low-level host behavior Plain ASP.NET Core gives full control. Use AppSurface only if the module hook makes the policy clearer. Use Plain ASP.NET Core When The setup is short, local, and obvious. The behavior belongs to only one app. The app already has a clear extension method or startup convention. A module would make the code harder to trace. This is not a failure. ASP.NET Core already has excellent primitives for middleware, routing, options, status pages, exception handling, and dependency injection. Use AppSurface When The setup has a name your team uses in conversation. The setup must behave the same way across services. The setup has sharp edges that deserve tests. The setup should live near package docs rather than inside each app\u0027s Program.cs . A team lead needs one documented startup convention that service owners can follow. The first proof in this docs path is browser status pages and production error pages. ASP.NET Core can handle those directly. AppSurface helps when the team wants one named behavior contract for browser HTML, API-friendly responses, preview routes, and safe production 500 pages. Pitfalls Do not adopt AppSurface to avoid learning ASP.NET Core. You still need to understand the host, middleware, routing, and options model. Do not standardize a concern before it has a real policy. A module with no policy is just indirection. Do not compare this Start Here path against larger frameworks. The honest first question is whether AppSurface is clearer than the plain ASP.NET Core startup code your team would otherwise write. Next: First Success Path","snippet":"Should I Use AppSurface? Start with plain ASP.NET Core. Reach for AppSurface when a startup concern is important enough to name, test, document, and reuse. That rule works for one service and for many services. A...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":["plain ASP.NET Core","why AppSurface","use AppSurface"],"keywords":["baseline","startup glue","module","Program.cs"],"status":null,"navGroup":"Start Here","publicSection":"start-here","publicSectionLabel":"Start Here","isSectionLanding":false,"order":20,"sequenceKey":"appsurface-evaluator","canonicalSlug":null,"relatedPages":["start-here/appsurface-evaluator.md","guides/from-program-cs-to-module.md"],"breadcrumbs":["Start Here","Should I Use AppSurface?"],"sourcePath":"start-here/should-i-use-appsurface.md"},{"id":"tools/forgetrust.appsurface.markdownsnippets","path":"/docs/tools/forgetrust.appsurface.markdownsnippets","title":"ForgeTrust.AppSurface.MarkdownSnippets","summary":"\u0060ForgeTrust.AppSurface.MarkdownSnippets\u0060 keeps checked-in Markdown code fences synchronized with source-owned samples. It is intentionally a generator and verifier only: rendered documentation consumes normal Markdown after the generated blocks have been materialized.","headings":["Commands","Managed Blocks","Source Markers","Pitfalls"],"bodyText":"ForgeTrust.AppSurface.MarkdownSnippets ForgeTrust.AppSurface.MarkdownSnippets keeps checked-in Markdown code fences synchronized with source-owned samples. It is intentionally a generator and verifier only: rendered documentation consumes normal Markdown after the generated blocks have been materialized. Commands Generate the default RazorWire README snippets: Bash # From the repository root: dotnet run --project tools/ForgeTrust.AppSurface.MarkdownSnippets/ForgeTrust.AppSurface.MarkdownSnippets.csproj -- generate Verify that generated snippets are current: Bash # From the repository root: dotnet run --project tools/ForgeTrust.AppSurface.MarkdownSnippets/ForgeTrust.AppSurface.MarkdownSnippets.csproj -- verify Both commands accept: --repo-root \u003Cpath\u003E : repository root. Defaults to the current directory. --document \u003Cpath\u003E : Markdown file to generate or verify. Defaults to Web/ForgeTrust.RazorWire/README.md . The documented dotnet run --project tools/... commands are intentionally repository-root commands because the project path and default --repo-root are both resolved from the current directory. From another directory, pass rooted paths for both --project and --repo-root , or cd to the repository root before running them. Managed Blocks Managed Markdown blocks use an opening directive, a generated fenced code block, and a closing directive: Markdown \u003C!-- appsurface:snippet id=\u0022razorwire-counter\u0022 file=\u0022examples/razorwire-mvc/Views/Shared/Components/Counter/Default.cshtml\u0022 marker=\u0022razorwire-counter\u0022 lang=\u0022cshtml\u0022 --\u003E \u0060\u0060\u0060 cshtml Generated content goes here. \u0060\u0060\u0060 \u003C!-- /appsurface:snippet --\u003E Supported directive attributes are: id : stable block identifier for error messages. file : repository-relative source file path. marker : source marker identifier to extract. lang : Markdown fence language. dedent : optional boolean. Defaults to true ; use false when leading indentation is meaningful. Unknown attributes, duplicate attributes, rooted paths, paths that escape the repository root, and file= paths that cross a symlink or reparse-point segment fail verification. Keep sample directories physically inside the repository rather than linking them in from elsewhere. When an opening directive is indented or quoted, generated fence, content, and closing directive lines keep the same Markdown line prefix. Use that form when a snippet block belongs inside a nested Markdown structure such as a list item or blockquote. Source Markers Sources own snippets with matching start and end markers: C# // docs:snippet razorwire-counter:start Console . WriteLine ( \u0022 hello \u0022 ) ; // docs:snippet razorwire-counter:end Razor and HTML comments are also supported: Razor @ * docs:snippet razorwire-counter:start * @ \u003C rw:scripts /\u003E @ * docs:snippet razorwire-counter:end * @ HTML \u003C!-- docs:snippet razorwire-counter:start --\u003E \u003C div \u003E \u003C/ div \u003E \u003C!-- docs:snippet razorwire-counter:end --\u003E Each marker pair must be unique, ordered, and contain non-empty content. Marker-like text inside strings does not count because markers must occupy the whole trimmed line. Pitfalls Run generate after changing marked source files, then commit both the source change and the generated Markdown change. CI runs verify and fails when the checked-in Markdown drifts from the source markers. Do not use this for render-time includes. RazorDocs and other Markdown renderers should receive ordinary generated Markdown so package documentation stays portable across GitHub, NuGet, and static export surfaces.","snippet":"ForgeTrust.AppSurface.MarkdownSnippets ForgeTrust.AppSurface.MarkdownSnippets keeps checked-in Markdown code fences synchronized with source-owned samples. It is intentionally a generator and verifier only: rendered...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.MarkdownSnippets"],"sourcePath":"tools/ForgeTrust.AppSurface.MarkdownSnippets/README.md"},{"id":"troubleshooting/startup-and-modules","path":"/docs/troubleshooting/startup-and-modules","title":"Troubleshoot Startup and Modules","summary":"Diagnose first-run module registration, dependency, configuration, route, static asset, docs surface, and package-choice failures.","headings":["Module Did Not Run","Symptom","Likely Cause","Check","Fix","Dependency Module Did Not Register","Configuration Failed At Startup","Web Route, Static Asset, Or Docs Surface Is Missing","Wrong Package Installed First"],"bodyText":"Troubleshoot Startup and Modules Use this page when the first run or first module does not behave as expected. Each section gives the symptom, likely cause, check, and fix. Start with the visible symptom. Startup failures often look like docs, route, or package issues at first, but the root cause is usually module registration, dependency order, configuration, or package choice. Module Did Not Run Symptom The app starts, but the service, middleware, endpoint, or option your module owns is missing. Likely Cause The root module did not register the module, or the app is running a different root module than the one you edited. Check Find the root module passed to WebApp\u003CTModule\u003E , ConsoleApp\u003CTModule\u003E , or AppSurfaceStartup\u003CTModule\u003E . Then check RegisterDependentModules . Fix Register the missing module through ModuleDependencyBuilder , or move the behavior into the root module if it is truly app-local. Dependency Module Did Not Register Symptom A module runs, but a service or option from another module is missing. Likely Cause The module assumes another AppSurface module is present but does not declare that dependency. Check Search for the service or option owner. If it lives in another module, the consuming module should register that dependency in RegisterDependentModules . Fix Add the dependency module explicitly. Do not duplicate the dependency module\u0027s service registrations in the consuming module. Configuration Failed At Startup Symptom Startup exits before the app begins listening, often with a configuration validation message. Likely Cause A strongly typed configuration value is missing or outside its allowed range. Check Run the config validation example to see the expected failure shape: Bash dotnet run --project examples/config-validation The error should name the key and rule without printing the attempted value. Fix Set the missing value, correct the value, or relax the validation rule if the module contract was too strict. Do not print configuration values while debugging. They may contain secrets. Web Route, Static Asset, Or Docs Surface Is Missing Symptom A web route returns 404 , a static asset is missing, or the docs surface does not appear where expected. Likely Cause The wrong module is registered, the app\u0027s host identity is not the assembly that owns static web assets, or the docs route root is not the one you are opening. Check Confirm the expected web module is registered. Confirm the startup log shows the URL you are opening. For RazorDocs, check whether the app is mounted at /docs or a configured docs root. For static web assets in custom hosts, check StartupContext.HostApplicationName and StartupContext.OverrideEntryPointAssembly . Fix Use the app\u0027s logged URL and configured docs root. When a custom host needs a different assembly identity, set StartupContext.OverrideEntryPointAssembly instead of overloading the display name. Wrong Package Installed First Symptom The app has extra packages, but the first example still does not map to the kind of app you are building. Likely Cause An optional package was installed before the base package or the package chooser was skipped. Check Read the AppSurface v0.1 package chooser . Start with the package that matches the app type. Fix For a normal ASP.NET Core app, start with ForgeTrust.AppSurface.Web . Add optional packages such as OpenAPI, Scalar, RazorWire, Tailwind, or RazorDocs only when the app needs them.","snippet":"Troubleshoot Startup and Modules Use this page when the first run or first module does not behave as expected. Each section gives the symptom, likely cause, check, and fix. Start with the visible symptom. Startup...","pageType":"troubleshooting","pageTypeLabel":"Troubleshooting","pageTypeVariant":"troubleshooting","audience":null,"component":null,"aliases":["module did not run","dependency module","config failed","wrong package"],"keywords":["StartupContext","IAppSurfaceModule","dependency","configuration"],"status":null,"navGroup":"Troubleshooting","publicSection":"troubleshooting","publicSectionLabel":"Troubleshooting","isSectionLanding":false,"order":10,"sequenceKey":null,"canonicalSlug":null,"relatedPages":["examples/config-validation/README.md","ForgeTrust.AppSurface.Core/README.md","packages/README.md"],"breadcrumbs":["Troubleshooting","Troubleshoot Startup and Modules"],"sourcePath":"troubleshooting/startup-and-modules.md"},{"id":"web","path":"/docs/web","title":"Web Projects","summary":"This directory contains libraries and tools specifically for web application development within the AppSurface ecosystem.","headings":["Contents"],"bodyText":"Web Projects This directory contains libraries and tools specifically for web application development within the AppSurface ecosystem. Need install guidance first? Start with the AppSurface v0.1 package chooser , then come back here for the deeper web-surface breakdown. Contents ForgeTrust.AppSurface.Web \u2013 The core web bootstrapping library, including conventional browser status pages and opt-in production 500 pages. ForgeTrust.AppSurface.Web.OpenApi \u2013 Modular OpenAPI generation. ForgeTrust.AppSurface.Docs \u2013 Reusable docs package for harvesting and serving repository documentation. ForgeTrust.AppSurface.Docs.Standalone \u2013 AppSurface host for exporting and serving RazorDocs. ForgeTrust.RazorWire \u2013 Reactive web components, real-time streaming, CDN-default static export, and convention-based failed form UX. ForgeTrust.AppSurface.Web.Scalar \u2013 Scalar API Reference UI integration. ForgeTrust.AppSurface.Web.Tests \u2013 Test suite for web components. \uD83C\uDFE0 Back to Root","snippet":"Web Projects This directory contains libraries and tools specifically for web application development within the AppSurface ecosystem. Need install guidance first? Start with the AppSurface v0.1 package chooser , then...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","Web Projects"],"sourcePath":"Web/README.md"},{"id":"web/forgetrust.appsurface.docs","path":"/docs/web/forgetrust.appsurface.docs","title":"ForgeTrust.AppSurface.Docs","summary":"Documentation site generation and hosting for AppSurface web applications.","headings":["Overview","What It Provides","Styling Boundary","Decision Matrix","Common Calls","Stylesheet Responsibilities","Internal Style Tokens","Terms","Pitfalls","Details Page Heading Ownership","Syntax-highlighted code blocks","Language aliases","Authoring pitfalls","Harvest Health","Status Contract","Diagnostics","Cancellation and Caching","Operator Health Routes","Strict Startup Failure","Configuration","Source-backed docs without versioning","Source-backed docs with published-version routing","Route contract","Route references"],"bodyText":"ForgeTrust.AppSurface.Docs Documentation site generation and hosting for AppSurface web applications. Overview ForgeTrust.AppSurface.Docs is the reusable Razor Class Library package behind the RazorDocs experience. It aggregates Markdown and C# API documentation into a browsable docs UI, supports an optional version archive for published releases, and is intended to be embedded into AppSurface web applications or used by the standalone RazorDocs host. If you are evaluating RazorDocs for your own repository, start with Use RazorDocs in your repository . That page explains the consumer model, host shape, authoring metadata, and adoption checklist before you drill into this package reference. What It Provides RazorDocsWebModule for wiring the docs UI into an AppSurface web host AddRazorDocs() for typed options binding and core service registration DocAggregator plus the built-in Markdown and C# harvesters, including structured harvest health diagnostics Search UI assets, page-local outline behavior, and the /docs MVC surface used by RazorDocs consumers DocsUrlBuilder plus the MVC surface used by RazorDocs consumers so the live docs root, search shell, and archive routes stay in one shared contract RazorDocsVersionCatalog plus RazorDocsVersionCatalogService for mounting exact published release trees and surfacing release-level status in the public archive Structured trust metadata plus a built-in trust bar for release notes, upgrade guides, and other pages that need status and provenance near the top Contributor provenance rendering with a Source of truth strip for source links, edit links, and relative Last updated timestamps on details pages Precompiled Tailwind-powered styling with layout-time path resolution for root-module and embedded hosts Styling Boundary When choosing where a new RazorDocs style should live, use this order: If the surface needs a reusable component contract or a selector shared across CSS and JavaScript, use a semantic class. Otherwise, if RazorDocs does not fully control the nested content markup, use wrapper-scoped semantic CSS. Otherwise, for one-off package chrome that RazorDocs owns directly, prefer Tailwind utility classes in markup. This section is the normative source of truth for the boundary. DESIGN.md explains why the rule exists and how to review edge cases. ROADMAP.md only points future work back to this contract. Decision Matrix Surface Default Why Real examples Exception / note One-off owned package chrome in Razor views Prefer Tailwind utility classes in markup RazorDocs fully owns the markup, so local utility classes keep intent obvious where the change happens docs landing shell in Views/Docs/Index.cshtml , sidebar shell and layout framing in Views/Shared/_Layout.cshtml , one-off page header spacing in Views/Docs/Details.cshtml If the same styling contract repeats across package surfaces, promote it to a semantic component class instead of copying long utility strings Reusable owned package components or stable cross-file UI selectors Use semantic component classes in the shared package stylesheet Shared selectors keep repeated UI stable across Razor, CSS, and sometimes JavaScript docs-page-badge , docs-metadata-chip , docs-page-meta , docs-provenance-strip , docs-trust-bar , and docs-outline-* in wwwroot/css/app.css Utilities can still handle surrounding layout and one-off placement Harvested or generated document bodies that RazorDocs does not fully author element by element Use wrapper-scoped semantic CSS such as .docs-content ... in the shared package stylesheet RazorDocs cannot safely push utility classes into nested harvested HTML headings, paragraphs, code blocks, overload groups, and namespace sections inside .docs-content in Views/Docs/Details.cshtml and wwwroot/css/app.css Do not rewrite harvested nested HTML just to satisfy utility-class purity JavaScript-generated or stateful UI that needs CSS and JavaScript to share stable hooks Use semantic hook classes, then style them in CSS Runtime UI needs stable names both the stylesheet and script can rely on search result rows, filter chips, active-filter pills, and state containers in wwwroot/docs/search.css and wwwroot/docs/search-client.js Use id values where uniqueness or ARIA wiring require them, but keep reusable styling and state contracts on semantic classes Common Calls New one-off page header spacing or typography in owned Razor markup: use Tailwind utilities in the view. New reusable badge, metadata chip, page metadata row, trust/provenance surface, or page-local outline state: add or extend a semantic component class in wwwroot/css/app.css , then use utilities around it only when they are purely local. For Views/Docs/Search.cshtml , keep the stateful search container or interactive hook semantic, but use local utilities for one-off header copy, helper layout, and fallback-link chrome inside that view. Restyling paragraphs, headings, or code blocks inside .docs-content : update wrapper-scoped CSS instead of pushing utility classes into harvested HTML. Markdown pages with long-form prose use .docs-content--markdown for prose measure, paragraph rhythm, list spacing, links, blockquotes, and inline code. Generated non-Markdown docs and docs marked with page_type: api or page_type: api-reference use .docs-content--api so signatures and reference tables keep the wider base content measure. New search filter pill, active-filter surface, or other stateful search UI: use a semantic hook class because CSS and JavaScript both need to recognize it. Stylesheet Responsibilities wwwroot/css/app.css is the Tailwind entry point for the generated package stylesheet ( site.gen.css ). It owns shared RazorDocs component primitives and wrapper-scoped document body styling because the generated stylesheet is loaded on every docs page before any search-specific assets. wwwroot/docs/search.css owns the search shell, interactive search controls, JavaScript-rendered result states, empty/failure states, and search skeletons. It should not define shared page badges, metadata chips, provenance strips, trust bars, or other primitives required by non-search docs pages. Internal Style Tokens wwwroot/css/app.css declares RazorDocs\u0027 shared dark-slate style tokens on :root with --docs-* custom properties. These tokens describe the current flagship visual system: slate surfaces, muted borders, readable text, cyan accents, focus rings, active fills, code chrome, table chrome, and skeleton treatments. The tokens are internal package implementation details. They ship in browser CSS because RazorDocs CSS ships to the browser, but hosts should not treat them as a supported override API yet. Future theming work can promote a documented public contract once the host customization model is designed. Use tokens when a value is either: repeated across two or more unrelated selector groups part of a documented repeated state such as focus, active selection, muted text, default border, raised surface, code chrome, table chrome, or skeleton loading Leave a raw literal local when naming it would lie about its scope. Allowed local categories are: syntax-highlight token colors such as keyword, string, comment, number, type, member, operator, inserted, and deleted spans API signature token colors used only to distinguish return values, parameters, modifiers, literals, and similar generated reference fragments one-off semantic page-type badge variants such as example, API/reference, glossary, FAQ, internals, and troubleshooting browser or generated-content details that do not represent a reusable design primitive Do not add broad fallbacks such as var(--docs-color-text-default, #e2e8f0) unless a generated asset, load-order, or host-embedding test proves the fallback is needed. The package-owned shared stylesheet should consume the internal tokens directly. wwwroot/docs/search.css is the exception: exact published release trees are allowed to carry only search.css as their required CSS asset, so it defines --docs-search-* fallback aliases that read the shared --docs-* tokens when available and preserve a self-contained search UI when the generated package stylesheet is absent. Terms Package chrome : one-off layout and presentation markup that RazorDocs owns directly, such as page shells, spacing, and framing. Harvested content : nested documentation HTML that RazorDocs renders but does not fully author element by element, such as the body inside .docs-content . Markdown prose surface : authored Markdown rendered with .docs-content--markdown ; it optimizes for reading dense release notes, guides, and README-style pages rather than for wide API signatures in generated reference docs. Stable selector / hook : a semantic class or required unique id that Razor, CSS, accessibility wiring, and sometimes JavaScript rely on consistently across files. Pitfalls Do not refactor between utilities and semantic CSS for purity alone. Follow the surface contract unless a real usability or maintainability problem exists. Do not treat required id values, such as docs-search-page-input or docs-search-page-filters-panel , as the reusable styling contract. They exist for uniqueness, targeting, and ARIA relationships. Do not assume every child inside a semantic search container needs its own semantic class; local typography and spacing inside one view can still stay inline. Do not add semantic classes to static package chrome when plain utilities are clearer and the styling is truly local. Do not place non-search primitives in wwwroot/docs/search.css just because the layout loads search assets globally today. Use wwwroot/css/app.css for shared components so future theming can target one stable package layer. Do not introduce new hardcoded slate/cyan literals inside shared selector groups. Add or reuse a --docs-* token instead. Do not move syntax-highlight colors into the shared token layer until RazorDocs has a public code-theme story. Code block chrome can use shared tokens; syntax spans stay local. Details Page Heading Ownership RazorDocs details pages render the page title in the package-owned shell for authored Markdown pages. The title comes from DocDetailsViewModel.Title , which resolves metadata title first, then a leading Markdown H1, then the harvested file or folder fallback. Because the shell already owns the semantic page H1, Views/Docs/Details.cshtml suppresses only a leading rendered Markdown \u003Ch1\u003E from the harvested body before writing .docs-content . This keeps source Markdown portable for GitHub and editor previews, where a top # Title is still useful, without showing duplicate page headings in RazorDocs. The suppression is intentionally narrow: It runs only when the details shell renders the H1. C# API reference pages keep their harvested body heading because the shell hides its top H1 for generated API content. It removes only the first body element when that element is an H1. Later H1 elements remain visible because they are body structure, not duplicated chrome. Namespace README intros apply the same rule before the README HTML is wrapped in .doc-namespace-intro , so # Namespace stays useful in source while the generated namespace shell remains the only page H1. For ordinary Markdown pages, suppression happens at render time. DocNode.Content , search extraction, and outline generation still see the harvested document as produced by the harvester. A leading Markdown H1 still participates in title resolution when explicit metadata title is absent, so README-style pages keep their authored title in the shell after the body H1 is suppressed. Pitfall: do not work around duplicate headings by removing the source # Title from README-style pages. That makes the file worse outside RazorDocs. Let the RazorDocs shell suppress the rendered duplicate instead. Syntax-highlighted code blocks RazorDocs renders fenced Markdown code blocks during Markdown harvest. Supported languages are highlighted server-side, so normal docs pages and exported docs do not need client-side Prism, highlight.js, or Shiki initialization after navigation. The v1 contract is RazorDocs-owned HTML: HTML \u003C pre class = \u0022 doc-code doc-code--highlighted doc-code--language-csharp language-csharp \u0022 \u003E \u003C span class = \u0022 doc-code__language \u0022 \u003E C# \u003C/ span \u003E \u003C code \u003E ... \u003C/ code \u003E \u003C/ pre \u003E Plain fallback uses the same shape with doc-code--plain . Token spans, when present, use doc-token plus semantic modifiers such as doc-token--keyword , doc-token--string , doc-token--comment , doc-token--number , doc-token--type , doc-token--member , doc-token--operator , and doc-token--punctuation . These classes are internal RazorDocs output in v1. They are stable enough for the package stylesheet and tests, but they are not a public custom highlighter API. Language aliases RazorDocs uses the first whitespace-delimited code-fence info token as the language. Metadata after the language is ignored in v1, so \u0060\u0060\u0060csharp {2} is treated as csharp without activating line markers. Authored token Normalized language cs , c# , csharp csharp razor , cshtml razor xml xml json json bash , sh , shell bash html html css css js , javascript javascript md , markdown markdown diff diff txt , text , plaintext plaintext Supported normalized languages render highlighted output when the bundled TextMateSharp grammar loads successfully. plaintext , unsupported languages, unknown languages, grammar failures, tokenization failures, and blocks above RazorDocs\u0027 internal size threshold render as escaped plaintext with the same quiet code-block treatment. A correct plain block is preferred over fake highlighting. Authoring pitfalls Do not paste raw HTML token spans into Markdown code fences. RazorDocs owns token markup. Do not rely on automatic language detection. Add the language token explicitly when highlighting matters. Do not assume every language alias supports custom semantics beyond normalization. Do not use Shiki or Expressive Code line-marker syntax yet. V1 ignores code-fence metadata after the language. Do not style highlighter output outside the RazorDocs package stylesheet. Code block styling belongs under .docs-content in wwwroot/css/app.css . Harvest Health DocAggregator.GetHarvestHealthAsync(CancellationToken) returns structured health for the same cached harvest snapshot used by docs pages, public sections, and the search index. Hosts should use this API when they need to report whether source-backed docs are healthy, empty by configuration, partially degraded, or unavailable because every harvester failed. C# var health = await docAggregator . GetHarvestHealthAsync ( ct ) ; if ( health . Status is DocHarvestHealthStatus . Failed or DocHarvestHealthStatus . Degraded ) { foreach ( var diagnostic in health . Diagnostics ) { var logLevel = diagnostic . Severity switch { DocHarvestDiagnosticSeverity . Information =\u003E LogLevel . Information , DocHarvestDiagnosticSeverity . Warning =\u003E LogLevel . Warning , DocHarvestDiagnosticSeverity . Error =\u003E LogLevel . Error , DocHarvestDiagnosticSeverity . Critical =\u003E LogLevel . Critical , _ =\u003E LogLevel . Warning } ; logger . Log ( logLevel , \u0022 RazorDocs harvest diagnostic {Code}: {Problem} {Fix} \u0022 , diagnostic . Code , diagnostic . Problem , diagnostic . Fix ) ; } } The returned DocHarvestHealthSnapshot includes: Status : the aggregate DocHarvestHealthStatus . GeneratedUtc : the timestamp for the cached snapshot generation. RepositoryRoot : the resolved source root passed to harvesters. Treat this as server-only operational data; redact or omit it before forwarding harvest health to client-visible UI or public APIs. TotalHarvesters , SuccessfulHarvesters , and FailedHarvesters : counts for the configured harvesters. TotalDocs : the number of documentation nodes in the final cached docs snapshot after RazorDocs post-processing. Harvesters : one DocHarvesterHealth entry per configured harvester, including its concrete type name, DocHarvesterHealthStatus , raw returned doc count, and optional diagnostic. Diagnostics : structured DocHarvestDiagnostic entries for harvester-level and aggregate states. RazorDocs-created snapshots never expose raw exception messages in diagnostics; exception details stay in host logs. Status Contract DocHarvestHealthStatus is intentionally distinct from HTTP or process health: Healthy : at least one configured harvester returned documentation and no harvester failed. Empty : harvesting completed without failures, but the final docs corpus is empty. This can be valid for an empty repository, a disabled source set, or a host with no registered harvesters. Degraded : at least one harvester succeeded or returned a valid empty result while another failed, timed out, or canceled. Docs remain usable, but the corpus may be incomplete. Failed : every configured harvester failed, timed out, or canceled. RazorDocs returns an empty corpus for compatibility, but the snapshot should be treated as an operational failure. DocHarvesterHealthStatus describes each source contribution: Succeeded : the harvester returned one or more docs. ReturnedEmpty : the harvester completed without error and returned no docs. Failed : the harvester threw while scanning. TimedOut : the harvester exceeded RazorDocs\u0027 per-harvester timeout budget. Canceled : the harvester observed cancellation outside RazorDocs\u0027 timeout budget. The public enum numeric values are stable compatibility contracts for consumers that persist, serialize, bind, or compare them. New members may be added later, but existing values must not be reordered or renumbered. Diagnostics Each DocHarvestDiagnostic has a stable Code , Severity , optional HarvesterType , operator-facing Problem , likely Cause , and suggested Fix . Use diagnostic codes for tests, dashboards, and host UI branching instead of parsing log messages. RazorDocs currently emits these codes: DocHarvestDiagnosticCodes.HarvesterTimedOut ( razordocs.harvest.harvester_timed_out ) DocHarvestDiagnosticCodes.HarvesterCanceled ( razordocs.harvest.harvester_canceled ) DocHarvestDiagnosticCodes.HarvesterFailed ( razordocs.harvest.harvester_failed ) DocHarvestDiagnosticCodes.NoHarvesters ( razordocs.harvest.no_harvesters ) DocHarvestDiagnosticCodes.AllFailed ( razordocs.harvest.all_failed ) DocHarvestDiagnosticCodes.DocReservedRouteCollision ( razordocs.routes.reserved_collision ) DocHarvestDiagnosticCodes.DocRouteCollision ( razordocs.routes.doc_collision ) DocHarvestDiagnosticCodes.DocRedirectAliasCollision ( razordocs.routes.redirect_alias_collision ) DocHarvestDiagnosticCodes.DocInvalidCanonicalSlug ( razordocs.routes.invalid_canonical_slug ) DocHarvestDiagnosticCodes.DocInvalidRedirectAlias ( razordocs.routes.invalid_redirect_alias ) DocHarvestDiagnosticCodes.DocLossySlugNormalization ( razordocs.routes.lossy_slug_normalization ) An all-failed snapshot logs one critical message when that snapshot is generated. Reusing the cached health snapshot does not log again. Calling InvalidateCache() and then reading docs or harvest health can generate a new snapshot and, if every harvester still fails, a new critical log entry. Cancellation and Caching GetHarvestHealthAsync(cancellationToken) observes caller cancellation only while the caller waits for the memoized snapshot. Canceling that wait does not cancel, poison, or evict the shared snapshot computation. A later caller can still receive the completed snapshot. Health and docs are computed from the same cached snapshot. This is deliberate: a host that reads GetDocsAsync() and then GetHarvestHealthAsync() sees health for the docs it is serving, not a second harvest with different timing or failures. Use InvalidateCache() when an operator explicitly asks RazorDocs to refresh source-backed docs. Operator Health Routes RazorDocs reserves a redacted operator health page at {DocsRootPath}/_health and a machine-readable JSON endpoint at {DocsRootPath}/_health.json ahead of the docs catch-all route. Both endpoints return health responses by default only when the host environment is Development ; otherwise they return 404 . Non-development hosts must opt in with RazorDocs:Harvest:Health:ExposeRoutes=Always . The JSON response uses the camelCase wire form of RazorDocsHarvestHealthResponse : status : Healthy , Empty , Degraded , or Failed . verification.ok : true for Healthy and Empty ; false for Degraded and Failed . verification.httpStatusCode : 200 for Healthy and Empty ; 503 for Degraded and Failed . generatedUtc , harvester counts, total docs, per-harvester status, and redacted diagnostics. The response omits RepositoryRoot , diagnostic Cause , raw exception messages, stack traces, and absolute filesystem paths. Health routes set Cache-Control: no-store, no-cache so local and CI checks do not pass or fail on stale operator data. The sidebar health entry follows RazorDocs:Harvest:Health:ShowChrome , which is independent from route exposure. This lets a host expose _health.json for a script without advertising the health page in the docs chrome, or show status-only chrome while the reserved health endpoints still return 404 . When chrome is visible but ExposeRoutes hides responses for the current environment, RazorDocs renders a non-clickable status chip instead of a link. JSON { \u0022 RazorDocs \u0022 : { \u0022 Harvest \u0022 : { \u0022 Health \u0022 : { \u0022 ExposeRoutes \u0022 : \u0022 DevelopmentOnly \u0022 , \u0022 ShowChrome \u0022 : \u0022 DevelopmentOnly \u0022 } } } } Allowed exposure values are DevelopmentOnly , Always , and Never . If you set ExposeRoutes=Always , the reserved health endpoints become an operator surface in that environment. Protect them with host-owned authentication, authorization, or network controls when they are reachable by untrusted users. Pitfalls Do not parse logs to infer harvest health. Use GetHarvestHealthAsync() and diagnostic codes. Do not treat Empty as a failure. It means RazorDocs found no docs without a failed harvester. Do not expect raw exception details in public diagnostics. Use host logs for stack traces and exception messages. Do not assume the health routes are ASP.NET Core IHealthCheck endpoints. They report documentation harvest health, not whole-application liveness. Do not set ExposeRoutes=Always on a public host without host-owned protection. Strict Startup Failure Set RazorDocs:Harvest:FailOnFailure to true when a host should fail during startup if the cached harvest-health snapshot is DocHarvestHealthStatus.Failed . JSON { \u0022 RazorDocs \u0022 : { \u0022 Harvest \u0022 : { \u0022 FailOnFailure \u0022 : true } } } Strict mode is built for CI and export hosts that publish docs artifacts. It prevents an all-failed harvest from becoming an empty or untrustworthy release tree. Leave it off for general public runtime hosts unless failing the whole application is the right operational posture for that host. The startup preflight calls DocAggregator.GetHarvestHealthAsync(CancellationToken) and reuses the normal cached docs snapshot. It does not run a second harvester pipeline. Healthy , Empty , and Degraded snapshots continue startup; only aggregate Failed throws RazorDocsHarvestFailedException . RazorDocsHarvestFailedException exposes a redacted DocHarvestFailureSummary with status, counts, timestamp, and diagnostic code/severity/problem/fix fields. It omits RepositoryRoot , raw exception messages, stack traces, and diagnostic Cause text. Host logs can still contain lower-level harvester diagnostics because those logs are operator data, not public exception payload. Configuration RazorDocs is still source-backed at runtime in this slice. RazorDocs:Mode should stay Source , and RazorDocs:Bundle remains reserved for a later reusable runtime-bundle host. Versioning in this slice does not change the runtime source mode; it adds a catalog that mounts already-exported release trees beside the live source-backed preview surface. Source-backed docs without versioning Use the default single-surface configuration when you want the live docs experience rooted directly at /docs : JSON { \u0022 RazorDocs \u0022 : { \u0022 Mode \u0022 : \u0022 Source \u0022 , \u0022 CacheExpirationMinutes \u0022 : 5 , \u0022 Source \u0022 : { \u0022 RepositoryRoot \u0022 : \u0022 /path/to/repo \u0022 } } } If RazorDocs:Source:RepositoryRoot is omitted, the package falls back to repository discovery from the app content root. To host the same live source surface somewhere else, set the route-family root. With versioning disabled, the live docs root defaults to the route root: JSON { \u0022 RazorDocs \u0022 : { \u0022 Routing \u0022 : { \u0022 RouteRootPath \u0022 : \u0022 /foo/bar \u0022 } } } That configuration serves the live docs home at /foo/bar , search at /foo/bar/search , and the live search index at /foo/bar/search-index.json . Source-backed docs with published-version routing Enable versioning when you want the host to keep serving the live unreleased snapshot from source while also mounting exact published release trees under stable public routes: JSON { \u0022 RazorDocs \u0022 : { \u0022 Mode \u0022 : \u0022 Source \u0022 , \u0022 Source \u0022 : { \u0022 RepositoryRoot \u0022 : \u0022 /path/to/repo \u0022 } , \u0022 Routing \u0022 : { \u0022 RouteRootPath \u0022 : \u0022 /foo/bar \u0022 , \u0022 DocsRootPath \u0022 : \u0022 /foo/bar/next \u0022 } , \u0022 Versioning \u0022 : { \u0022 Enabled \u0022 : true , \u0022 CatalogPath \u0022 : \u0022 artifacts/razordocs/versions.json \u0022 } } } The route-family root owns the stable entry alias, archive, and exact release routes. The docs root owns the live source-backed preview. In the example above, /foo/bar is the recommended-release alias, /foo/bar/versions is the archive, /foo/bar/v/{version} serves immutable release trees, and /foo/bar/next remains the live preview. Route contract RazorDocs keeps two roots on purpose: RazorDocs:Routing:RouteRootPath is the route-family root. It owns the stable entry alias, public archive, and exact-version release routes. RazorDocs:Routing:DocsRootPath is the live source-backed docs root. It owns current docs pages, the current search shell, and the current search-index.json . Default routing: Configuration Route root Live docs root Archive Exact versions Versioning off, no routing config /docs /docs /docs/versions /docs/v/{version} Versioning on, no routing config /docs /docs/next /docs/versions /docs/v/{version} Versioning off, RouteRootPath=/foo/bar /foo/bar /foo/bar /foo/bar/versions /foo/bar/v/{version} Versioning on, RouteRootPath=/foo/bar /foo/bar /foo/bar/next /foo/bar/versions /foo/bar/v/{version} Versioning on, RouteRootPath=/ / /next /versions /v/{version} DocsRootPath can be configured explicitly, but RazorDocs does not infer RouteRootPath by stripping /next or any other suffix. If you want versioned docs under /foo/bar , configure RouteRootPath=/foo/bar ; setting only DocsRootPath=/foo/bar/next keeps the route family at the default /docs . RazorDocs registers only the configured docs routes. It does not add a generic {controller}/{action} fallback to the host application, so custom docs roots stay isolated from other modules and application routes. Route references Consumers should resolve DocsUrlBuilder and use DocsUrlBuilder.Routes instead of hardcoding route strings: C# var routes = app . Services . GetRequiredService \u003C DocsUrlBuilder \u003E ( ) . Routes ; var home = routes . Home ; var search = routes . Search ; var searchIndexRefresh = routes . SearchIndexRefresh ; var healthJson = routes . HealthJson ; RazorDocsRouteReferences contains Home , Search , SearchIndex , SearchIndexRefresh , Versions , Health , and HealthJson . These values are app-relative. Apply HttpRequest.PathBase , Url.PathBaseAware(...) , or the host\u0027s equivalent presentation helper only at browser-facing boundaries. Document route identity RazorDocs assigns each cached snapshot a route identity catalog. The catalog keeps source identity separate from browser-facing route identity, so authors can keep Markdown source links portable while readers see structured URLs. Default route behavior: Markdown files publish without .md.html . For example, start-here/appsurface-evaluator.md publishes at {DocsRootPath}/start-here/appsurface-evaluator . README.md , README.markdown , index.md , and index.markdown collapse to their containing directory. For example, packages/README.md publishes at {DocsRootPath}/packages . Source-shaped Markdown requests for public pages, including copy-pasted paths such as {DocsRootPath}/packages/README.md or {DocsRootPath}/guides/start.md , permanently redirect to the clean public route. Collision losers and reserved-route conflicts still stay non-public. The repository-root README represents the docs home and appears in search as {DocsRootPath} . It is not rendered through /README.md . Generated API docs and other non-Markdown docs keep the existing .html route shape, such as {DocsRootPath}/Namespaces/ForgeTrust.AppSurface.Web.html . Fragments stay fragments. A harvested source path like guides/intro.md#setup publishes as {DocsRootPath}/guides/intro#setup . RazorDocs reserves document routes that belong to chrome, health, search, sections, versions, and assets. The reserved set includes the docs home, search , search-index.json , _health , _health.json , search.css , search-client.js , outline-client.js , minisearch.min.js , versions , and the sections/ and v/ route prefixes. Docs that resolve to reserved routes remain internally available for source lookup, but they are not public document winners and emit route diagnostics. Markdown route segments are normalized deterministically: Unicode is folded where possible, non-spacing marks are removed, ASCII letters are lower-cased, dots are preserved, and unsafe separators become hyphens. When that conversion is lossy, RazorDocs emits DocLossySlugNormalization so authors can decide whether to set an explicit route. Use canonical_slug when the source path is not the right reader-facing URL: yaml title: Should I Use AppSurface? canonical_slug: start-here/evaluator Use redirect_aliases for deliberate migrations: yaml title: Should I Use AppSurface? canonical_slug: start-here/evaluator redirect_aliases: - start-here/appsurface-evaluator - start-here/appsurface-evaluator.md.html canonical_slug and redirect_aliases are docs-root-relative route paths. Do not include a query string, fragment, leading docs root, or host name. Canonical slugs use the same deterministic segment normalization as source-derived Markdown routes. Redirect aliases preserve their literal authored route text after separator cleanup, so legacy URLs such as Old_Path/Guide.md.html keep their existing shape instead of being slugified. Aliases redirect permanently to the public canonical route and preserve the request query string. Public Markdown source paths such as /docs/foo.md and /docs/foo.md.html also redirect to the clean route so GitHub-style copy-pasted links recover automatically. Use redirect_aliases for non-source legacy URLs, renamed pages, and old route shapes that are not already implied by the source path. Declared aliases that try to shadow another public Markdown source path are ignored with a DocRedirectAliasCollision diagnostic so copy-pasted source URLs keep pointing at their owning page. Option reference RazorDocs:Mode Keep this at Source in this slice. Bundle still validates as unsupported because reusable request-time bundle hosting is deferred. RazorDocs:Source:RepositoryRoot Optional absolute or app-relative repository root for source harvesting. When omitted, RazorDocs falls back to repository discovery from the content root. RazorDocs:Harvest:FailOnFailure Defaults to false . AddRazorDocs() always registers RazorDocsHarvestFailurePreflightService ; this flag controls whether that preflight can fail startup. When true , the preflight fails the host with RazorDocsHarvestFailedException only when aggregate harvest health is Failed . Use this for release publishing, static export, and CI smoke hosts where publishing empty or untrustworthy docs is worse than a failed build. Do not use this expecting Empty or Degraded to fail in v1. Empty docs can be intentional, and degraded docs can still be usable. RazorDocs:Harvest:Health:ExposeRoutes Defaults to DevelopmentOnly . Controls whether {DocsRootPath}/_health and {DocsRootPath}/_health.json return health responses. RazorDocs always reserves the endpoint patterns before the docs catch-all route so health URLs do not fall through to document lookup. Always exposes the responses in non-development environments; protect the endpoints at the host boundary when they are publicly reachable. Never keeps the reserved endpoints returning 404 , including in development. RazorDocs:Harvest:Health:ShowChrome Defaults to DevelopmentOnly . Controls whether the built-in sidebar shows health status chrome. This is independent from ExposeRoutes so machine-readable checks and visible docs chrome can be configured separately. If routes are hidden for the current environment, the sidebar renders status-only chrome without an href . RazorDocs:Routing:RouteRootPath Controls the route-family root for stable entry, archive, and exact-version routes. Defaults to /docs when versioning is on. Defaults to DocsRootPath when versioning is off. Relative-looking values such as foo/bar are normalized to app-relative paths like /foo/bar during AddRazorDocs() post-configuration. / is supported for single-purpose root-mounted docs hosts. The path must be app-relative, must not end with / except for / , cannot contain query or fragment segments, and cannot be a reserved child such as /foo/bar/versions or /foo/bar/v . RazorDocs:CacheExpirationMinutes Controls the absolute lifetime of the shared docs snapshot that backs docs pages, public-section data, and {DocsRootPath}/search-index.json ; for example, /docs/search-index.json by default or /docs/next/search-index.json when RazorDocs:Routing:DocsRootPath is /docs/next . Defaults to 5 minutes. Must be a finite positive number from 0.016666666666666666 through 35791394.1 , inclusive. Must map to a whole number of seconds, because {DocsRootPath}/search-index.json uses the same duration for its private Cache-Control max-age header. Do not use 0 , sub-second values, or extreme values such as double.MaxValue ; RazorDocs rejects values outside the supported range during options validation. RazorDocs:Routing:DocsRootPath Controls the live source-backed docs root. Defaults to the route root when versioning is off. Defaults to {RouteRootPath}/next when versioning is on. Relative-looking values such as foo/bar/preview are normalized to app-relative paths like /foo/bar/preview during AddRazorDocs() post-configuration. / is supported for single-purpose unversioned docs hosts. The path must be app-relative, must not end with / except for / , and cannot contain query or fragment segments. When versioning is on, it cannot equal the route root and cannot use the route root\u0027s reserved archive or exact-version children, such as /foo/bar/versions , /foo/bar/v , or /foo/bar/v/1.2.3 . RazorDocs:Versioning:Enabled Turns on the published-version route contract and archive surface. Does not switch the runtime into bundle mode. RazorDocs:Versioning:CatalogPath Required when versioning is enabled. Points to the JSON catalog that describes the published exact-version trees and the recommended release alias. Relative paths resolve from the app content root. Published version catalog The version catalog is the release-level source of truth for version routing and archive presentation: JSON { \u0022 recommendedVersion \u0022 : \u0022 1.2.3 \u0022 , \u0022 versions \u0022 : [ { \u0022 version \u0022 : \u0022 1.2.3 \u0022 , \u0022 label \u0022 : \u0022 1.2.3 (Current) \u0022 , \u0022 summary \u0022 : \u0022 Recommended release for new evaluations and adoption. \u0022 , \u0022 exactTreePath \u0022 : \u0022 ./releases/1.2.3 \u0022 , \u0022 supportState \u0022 : \u0022 Current \u0022 , \u0022 visibility \u0022 : \u0022 Public \u0022 , \u0022 advisoryState \u0022 : \u0022 None \u0022 } , { \u0022 version \u0022 : \u0022 1.1.0 \u0022 , \u0022 label \u0022 : \u0022 1.1.0 \u0022 , \u0022 summary \u0022 : \u0022 Supported for teams finishing an upgrade. \u0022 , \u0022 exactTreePath \u0022 : \u0022 ./releases/1.1.0 \u0022 , \u0022 supportState \u0022 : \u0022 Maintained \u0022 , \u0022 visibility \u0022 : \u0022 Public \u0022 , \u0022 advisoryState \u0022 : \u0022 Vulnerable \u0022 } ] } recommendedVersion Exact version string that should also be mounted at RouteRootPath . Must point at a public, available version or the route-root entry falls back to the archive-style recovery surface. versions[].version Exact version identifier such as 1.2.3 or 1.2.3-rc.1 . versions[].label Optional reader-facing label shown in the archive. Defaults to version . versions[].summary Optional archive summary copy. versions[].exactTreePath Path to the exported stable docs subtree for one exact release. Relative paths resolve from the directory containing the catalog file. RazorDocs can mount that same artifact at RouteRootPath for the recommended alias and at {RouteRootPath}/v/{version} for the exact release surface. versions[].supportState Archive posture badge. Supported values are Current , Maintained , Deprecated , and Archived . versions[].visibility Archive visibility policy. Supported values are Public and Hidden . versions[].advisoryState Release-level warning badge. Supported values are None , Vulnerable , and SecurityRisk . Exact-version tree contract Each exactTreePath directory is treated as a prebuilt static subtree for one exact release. It is usually exported from the stable /docs surface, and at minimum it must include: index.html at the tree root search.html at the tree root search-index.json at the tree root The payload must remain valid JSON with a top-level documents array so version-local search can load safely. Every documents[] entry must include non-empty string path and title properties. Missing or blank path / title values cause RazorDocs to reject the published release tree during startup validation. search.css at the tree root. The bundled search stylesheet carries search-local fallbacks for the shared style tokens so exact release search controls remain styled even when a historical/static export does not include site.gen.css . search-client.js at the tree root outline-client.js at the tree root for outline-aware exports whose HTML references the page-local outline runtime minisearch.min.js at the tree root any section, detail, partial, and asset routes that belong to the exported docs surface for that release RazorDocs does not regenerate these trees at request time. It resolves extensionless requests back to the exported .html files and rewrites stable-root HTML plus search-index.json payloads so the same artifact can serve both the recommended alias and {RouteRootPath}/v/{version} honestly, including custom roots such as /foo/bar . Exporters should validate search-index.json , search.css , search-client.js , minisearch.min.js , and, for outline-aware exports, outline-client.js before publishing because a missing required runtime asset or a malformed search payload keeps that release unavailable or incomplete until the artifact is fixed. The version catalog intentionally does not crawl historical HTML to infer optional outline support; old exact archives stay immutable, and any future modernization should be an explicit rebuild from source into a new self-contained tree. Use the RazorWire CLI or another static-export pipeline to publish those trees ahead of time. Archive ordering The public archive preserves the authored order of versions[] from the catalog. Use that list order when you want a specific narrative ordering that differs from plain lexical version sorting. Availability and failure behavior Version validation is best-effort and release-local. A missing or malformed exactTreePath marks only that release unavailable. Healthy published versions and the live preview surface continue to load. If the configured recommendedVersion is hidden, missing, or unavailable, RazorDocs does not mount it at the route root; that entry route falls back to the archive-style recovery surface with a link to the live preview. Pitfalls Do not set RazorDocs:Routing:DocsRootPath to the same value as RouteRootPath when versioning is enabled. That collides with the stable published-release alias. Do not configure only DocsRootPath=/foo/bar/next and expect archive routes to move to /foo/bar ; set RouteRootPath=/foo/bar explicitly. Do not point recommendedVersion at a hidden or broken release tree. Do not assume RazorDocs:Versioning:Enabled means the runtime can read request-time bundles. This slice still serves the live preview from source and mounts published releases as static trees. Do not forget search-index.json in an exported release tree. A release without it is intentionally marked unavailable. RazorDocs:CacheExpirationMinutes is interpreted as minutes. Use shorter values for source-backed development hosts where authors need edits to appear quickly; use longer values for production hosts when harvesters are expensive or the docs corpus changes only during deploys. Pitfalls: Do not set CacheExpirationMinutes to 0 to disable caching. RazorDocs rejects zero and negative values because every request would rebuild the docs snapshot and search index. Do not set tiny positive values below 0.016666666666666666 minutes; the search-index Cache-Control max-age header cannot represent sub-second cache lifetimes. Do not set fractional-second values such as 0.333 minutes. RazorDocs rejects values that cannot round-trip to a whole-second max-age . Do not set huge finite values such as double.MaxValue . RazorDocs caps the value so the derived search-index Cache-Control max-age remains representable. The search-index response uses the same duration for its private Cache-Control max-age , so client refresh behavior stays aligned with server-side snapshot reuse. Manual refresh through {DocsRootPath}/search-index.json?refresh=1 still invalidates the server snapshot generation immediately for authenticated users; it does not change the configured TTL for later entries. For example, when RazorDocs:Routing:DocsRootPath is /docs/next , use /docs/next/search-index.json?refresh=1 . Contributor Provenance RazorDocs can render a lightweight Source of truth strip directly under the page title and summary on details pages. The strip is evidence-driven: View source links to the authored source when RazorDocs can identify one safely. Edit this page links to an edit surface when the host configures one safely. Last updated renders as relative time with an exact machine-readable \u003Ctime datetime=\u0022...\u0022\u003E value behind it. If a page has no trustworthy contributor evidence, RazorDocs omits the strip entirely instead of rendering placeholder copy. Host configuration Contributor provenance is configured under RazorDocs:Contributor : JSON { \u0022 RazorDocs \u0022 : { \u0022 Mode \u0022 : \u0022 Source \u0022 , \u0022 Source \u0022 : { \u0022 RepositoryRoot \u0022 : \u0022 /path/to/repo \u0022 } , \u0022 Contributor \u0022 : { \u0022 Enabled \u0022 : true , \u0022 DefaultBranch \u0022 : \u0022 main \u0022 , \u0022 SourceRef \u0022 : \u0022 8b7c6d5 \u0022 , \u0022 SourceUrlTemplate \u0022 : \u0022 https://github.com/forge-trust/AppSurface/blob/{branch}/{path} \u0022 , \u0022 SymbolSourceUrlTemplate \u0022 : \u0022 https://github.com/forge-trust/AppSurface/blob/{ref}/{path}#L{line} \u0022 , \u0022 EditUrlTemplate \u0022 : \u0022 https://github.com/forge-trust/AppSurface/edit/{branch}/{path} \u0022 , \u0022 LastUpdatedMode \u0022 : \u0022 Git \u0022 } } } Field behavior: Enabled defaults to true . Set it to false to disable all contributor provenance rendering. DefaultBranch is the stable branch or ref used when expanding configured source and edit templates, and the fallback source ref for symbol links. SourceRef is the preferred ref for generated C# API symbol links. Use a commit SHA when the docs build knows one. SourceUrlTemplate and EditUrlTemplate support only {branch} and {path} tokens, and configured templates must include {path} so each page expands to its own source or edit target. SymbolSourceUrlTemplate supports only {path} , {line} , {branch} , and {ref} for generated C# API symbol links. It must include {path} and {line} . LastUpdatedMode supports None and Git . None is the default so hosts opt into git-backed freshness explicitly; Git resolves freshness from local repository history when a trustworthy source path exists. Host contract: If Enabled is false , RazorDocs skips contributor rendering and does not enforce DefaultBranch or {path} template requirements at startup. If Enabled is true and SourceUrlTemplate or EditUrlTemplate is configured, DefaultBranch is required and RazorDocs fails options validation on startup when it is missing. If Enabled is true and SourceUrlTemplate or EditUrlTemplate is configured, that template must contain {path} . RazorDocs rejects startup when a template would collapse every page to one shared URL. If Enabled is true and SymbolSourceUrlTemplate is configured, the template must contain {path} and {line} , and unsupported {token} placeholders are rejected at startup. If it contains {ref} , RazorDocs uses SourceRef first and falls back to DefaultBranch ; one of those values must be configured. If it contains {branch} , DefaultBranch must be configured. Templates expand both the branch and normalized source path segment-by-segment, so slash-separated refs stay readable while spaces and other special characters are still URL-escaped safely. Git-backed freshness runs during docs snapshot generation, not during view rendering. RazorDocs uses a bounded snapshot-time freshness budget so slow or wedged git lookups degrade to omitted timestamps instead of stretching one timeout across the whole docs corpus. If git is unavailable, shallow, or missing history for a page, RazorDocs omits only Last updated . Hosts that want LastUpdatedMode: Git in CI or export jobs must provide real history for the docs checkout. For GitHub Actions, use actions/checkout with fetch-depth: 0 or another checkout shape that preserves commit history for the rendered files. C# symbol source links Generated C# API pages can render small Source links beside documented types, enums, method overloads, and properties. These are symbol-level links, not page-level namespace links. Namespace API pages are synthetic and may contain declarations from many files, so RazorDocs only links a generated API symbol when the harvester captured an exact source path and 1-based declaration line for that rendered anchor. SymbolSourceUrlTemplate is separate from SourceUrlTemplate because symbol links need {line} and page-level Markdown links do not. Prefer {ref} with SourceRef when publishing docs from CI so readers jump to the same code version used to build the docs: JSON { \u0022 RazorDocs \u0022 : { \u0022 Contributor \u0022 : { \u0022 DefaultBranch \u0022 : \u0022 main \u0022 , \u0022 SourceRef \u0022 : \u0022 8b7c6d5 \u0022 , \u0022 SymbolSourceUrlTemplate \u0022 : \u0022 https://github.com/forge-trust/AppSurface/blob/{ref}/{path}#L{line} \u0022 } } } Custom harvesters can populate DocNode.SymbolSourceProvenance , but RazorDocs only renders links for content that also includes the compatible placeholder emitted by the built-in C# harvester. The current placeholder contract is an implementation detail for generated API HTML: HTML \u003C span data-razordocs-symbol-source = \u0022 anchor-id \u0022 \u003E \u003C/ span \u003E RazorDocs expands or removes those placeholders during snapshot generation before HTML sanitization runs. If a placeholder has no safe href, if the source path is not repository-relative, if the line number is invalid, if duplicate placeholders make an anchor ambiguous, or if multiple provenance entries claim the same anchor, RazorDocs omits the symbol link. A missing link is better than a confident wrong line. When a namespace README is merged into a generated namespace API page, the page-level strip still points to the README source and uses the label Namespace intro source . The generated API symbols on the same page use their own inline Source links. Page-level overrides Authors can supply a nested contributor: block in inline Markdown front matter or in a paired sidecar such as page.md.yml : yaml contributor: hide_contributor_info: true source_path_override: Web/ForgeTrust.AppSurface.Docs/README.md source_url_override: https://github.com/forge-trust/AppSurface/blob/main/Web/ForgeTrust.AppSurface.Docs/README.md edit_url_override: https://github.com/forge-trust/AppSurface/edit/main/Web/ForgeTrust.AppSurface.Docs/README.md last_updated_override: 2026-04-22T23:19:00Z Field behavior: hide_contributor_info: true suppresses the strip entirely for that page. source_path_override feeds template expansion and git freshness when the rendered page does not map cleanly to DocNode.Path . It must stay repository-relative; rooted paths and traversal segments are ignored. source_url_override and edit_url_override bypass template generation entirely. RazorDocs accepts only absolute http / https URLs or root-relative paths for these overrides. last_updated_override must stay a real timestamp. RazorDocs renders it through the same relative-time treatment as git-backed freshness. Automatic versus explicit provenance RazorDocs is intentionally conservative about automatic provenance: Markdown pages use their harvested source path automatically. Harvested C# API symbols can get inline source links when SymbolSourceUrlTemplate is configured, but namespace-synthetic pages do not get one automatic page-level C# source link. Synthetic or merged pages can still opt into source, edit, or freshness evidence through explicit contributor: overrides. This keeps RazorDocs from inventing fake precision for pages that do not have one trustworthy underlying source file. Pitfalls Do not configure source or edit templates without DefaultBranch . RazorDocs rejects that startup shape because local git state is too brittle to guess from. Do not configure source or edit templates without {path} . That shape cannot identify one source file per page, so RazorDocs rejects it at startup. Do not author free-text freshness copy in the provenance strip. Use last_updated_override for an exact timestamp, and use trust.freshness for broader lifecycle guidance. Do not expect shallow CI clones to populate Last updated . RazorDocs degrades safely by omitting freshness when history is unavailable. In GitHub Actions, prefer actions/checkout with fetch-depth: 0 for pages that should surface git-backed freshness. Do not add {line} to SourceUrlTemplate ; use SymbolSourceUrlTemplate for symbol links so Markdown page provenance keeps working. Do not invent additional SymbolSourceUrlTemplate tokens. RazorDocs rejects unsupported placeholders such as {commit} or {linen} instead of rendering silently broken links. Do not expect automatic edit links on namespace-synthetic API pages. Symbol links point to source browsing locations, while README-authored namespace intros keep the page-level edit link. Namespace README Intros RazorDocs can merge an authored README.md into a generated namespace API page so teams can explain a namespace in prose without replacing the generated symbol list. Authoring contract A README qualifies as a namespace intro only when all of these are true: The C# API harvester generated a namespace page at Namespaces/{Dotted.Namespace} . The authored file is named README.md . The README is harvested as a root documentation node, not as a child fragment. The README directory resolves to the same dotted namespace as the generated page. The path has an explicit docs-owned prefix before the namespace directory, currently a docs/ segment or a Namespaces/ segment. Positive examples: README path Merged target docs/ForgeTrust.AppSurface.Web/README.md Namespaces/ForgeTrust.AppSurface.Web Namespaces/ForgeTrust.AppSurface.Web/README.md Namespaces/ForgeTrust.AppSurface.Web Negative examples: README path Behavior Web/ForgeTrust.AppSurface.Web/README.md Stays a package README page. src/ForgeTrust.AppSurface.Web/README.md Stays a source-adjacent README page if harvested. README.md Stays the repository-root docs landing source. docs/Unknown.Namespace/README.md Stays a normal README page unless a generated Namespaces/Unknown.Namespace page exists. Merge behavior The generated namespace page keeps its Namespaces/{Dotted.Namespace} route. README HTML is inserted into the namespace page as the namespace intro. A leading README H1 is suppressed during merge because the namespace page shell already renders the page H1. The standalone README node is removed after a successful merge so readers do not see duplicate pages. README metadata can override the namespace page metadata, but derived Markdown defaults are ignored when they would accidentally replace API-reference classification. README-relative links are resolved from the README source path before the standalone README page is removed. Links that target the removed README page itself are not rewritten to a published page. Avoid self-links such as ./README.md inside namespace intros because the standalone README route disappears after merge. Contributor provenance points at the README source, while symbol-level source links still point at the generated API declarations. Decision guidance Use a namespace README when the content is specifically about the namespace API surface: concepts, intended usage, lifecycle notes, or cross-type orientation for that namespace. Use a package README when the content is about package adoption: installation, package-level configuration, examples, compatibility, and links to broader guides. Package READMEs such as Web/ForgeTrust.AppSurface.Web/README.md and src/ForgeTrust.AppSurface.Web/README.md do not automatically become namespace intros, even when the folder name matches a namespace. That boundary is intentional so package docs do not disappear into API pages by folder-name coincidence. Future dual-use package and namespace docs should use an explicit opt-in contract instead of reopening implicit path matching. At the product-contract level, a future design could use a front matter flag that names the target namespace, a paired sidecar mapping a README to Namespaces/{Dotted.Namespace} , or a resolver extension point that receives an explicit namespace target. This repository should still prefer sidecar or resolver-based opt-in for authored README.md files because repository and package READMEs are expected to stay portable and free of inline front matter. Any future design should require the namespace name to be authored directly, preserve predictable package-doc behavior, and fail closed when the target namespace page does not exist. Pitfalls Do not move package READMEs under package folders expecting them to merge into namespace pages. Do not rely on the final folder name alone. A path needs a docs-owned prefix before the namespace directory. Do not expect a README to create a namespace API page. It only merges into a namespace page produced by the C# harvester. Do not include README self-links such as ./README.md in a namespace intro. Link to surviving guide pages, generated namespace anchors, or package docs instead. Do not use namespace README merging as a general redirect or alias mechanism. Use explicit metadata and link authoring for those behaviors. Usage Reference the package and add the module to your AppSurface web application: C# await WebApp \u003C RazorDocsWebModule \u003E . RunAsync ( args ) ; Public Sections RazorDocs now organizes public documentation around a fixed section-first model instead of a flat directory-first landing. Built-in sections Start Here Concepts How-to Guides Examples API Reference Releases Troubleshooting Internals These sections back the current docs home, the sidebar shell, and the dedicated section routes under the current docs surface, for example {DocsRootPath}/sections/{slug} . nav_group normalization and fallback rules nav_group can explicitly select a built-in public section by canonical label, slug, or alias. Invalid explicit nav_group values log a warning and fall back to RazorDocs-derived section assignment instead of creating ad hoc groups. Markdown docs with no explicit nav_group are derived into built-in sections using path and filename heuristics: repository-root README.md and start-like names such as quickstart or getting-started fall into Start Here examples/ content falls into Examples releases/ content and root changelogs fall into Releases concepts, architecture, explanation, and glossary-style paths fall into Concepts troubleshooting, faq, debug, and error-oriented paths fall into Troubleshooting internal-oriented paths fall into Internals anything else falls into How-to Guides API reference content continues to use the canonical API Reference section. API reference sidebar shape The primary sidebar keeps API Reference collapsed at the package and namespace level. Generated type and member anchors stay available from the namespace page itself through On this page , source links, and search, but they are not emitted as nested links in the global left rail. Deeper namespaces nest under the nearest namespace page that exists in the sidebar and use only their leaf label, so AppSurface.Core can show child links such as Defaults and Extensions instead of repeating AppSurface.Core.Defaults and AppSurface.Core.Extensions . This keeps large harvested API surfaces browsable without making readers scan hundreds of symbols before they intentionally open a namespace page. Configure RazorDocs:Sidebar:NamespacePrefixes when a host wants package names shortened in that rail. For example, ForgeTrust.AppSurface. turns ForgeTrust.AppSurface.Docs.Services into a Web family heading with RazorDocs.Services as the namespace link label. Section routes and landing docs The current docs surface exposes section routes such as {DocsRootPath}/sections/start-here . Only canonical slugs are served directly; label- or alias-shaped section requests redirect to the canonical section route. When a section has an authored landing doc, RazorDocs redirects the section route to that page. Sections with visible pages but no landing doc render a grouped fallback section page instead of a dead end. Invalid slugs or sections with no public pages render an unavailable section surface with recovery links back to the current docs home and Start Here . section_landing Use section_landing: true on a page to mark it as the authored entry point for its public section. yaml title: Start Here nav_group: Start Here section_landing: true summary: Start with the strongest evaluator proof path before drilling into implementation detail. Field behavior and pitfalls: The page must still belong to a valid built-in public section through explicit or derived nav_group . If multiple docs in one section set section_landing: true , RazorDocs keeps the lowest order value, then the lowest canonical path, and logs a warning for the others. A section landing doc can also author featured_page_groups ; RazorDocs uses those reader-intent groups for section-level \u201Cnext steps\u201D on the detail page and collapses the first resolved rows into section preview links surfaced on the current docs home. HideFromPublicNav = true always wins. Hidden pages do not appear in section routes, the sidebar, the docs home, or the public search index even if they declare a section or landing status. Default harvesting excludes test-project directories such as Tests , Test , *.Tests , *.UnitTests , and *.IntegrationTests . The C# harvester also skips examples directories so example README walkthroughs can stay public without publishing generated API reference for example application internals. Docs Link Authoring RazorDocs rewrites links inside harvested Markdown so authors can use source-friendly paths while readers stay on public docs-surface routes such as {DocsRootPath}/start-here/appsurface-evaluator with Turbo history support. Authoring contract Link to another harvested doc with its source path, such as ./guide.md , ../CHANGELOG.md , or /releases/unreleased.md . Link to an already public docs route only when the target is a harvested doc, such as /docs/releases/unreleased , /docs/next/releases/unreleased , or a custom-root equivalent like /foo/bar/releases/unreleased . Use ordinary site URLs, such as /privacy.html or ../status.html , for non-doc pages. RazorDocs leaves those links untouched. Use browser-facing URLs for metadata fields that render plain anchors without content rewriting, such as trust.migration.href . Catalog-backed rewriting During aggregation, RazorDocs builds a route identity catalog from the harvested documentation nodes. Link rewriting consults that catalog before converting any source or public-looking link into the active docs surface. This means a link is rewritten only when the target exists in the harvested docs set. A missing ./guide.md , an ambiguous docs route like /docs/missing , or a normal site page like ../privacy.html remains authored as-is instead of being guessed into a broken docs route. Pitfalls Do not rely on file extensions alone. A .md , .cs , or .html suffix does not make a link a RazorDocs target unless the target was harvested. If a doc link is not rewritten, first confirm the target file is included by the active harvester and not excluded by directory policy. Public docs-surface links are safe for exported docs, but source-relative Markdown links are usually easier to keep portable in GitHub and editor previews. Landing Curation RazorDocs can turn the root docs landing into a curated reader-intent surface by reading featured_page_groups from the repository-root README.md metadata. Authoring contract featured_page_groups is parsed as part of DocMetadata , so the metadata contract stays page-agnostic. RazorDocs uses those groups in two places: the root README.md metadata drives grouped proof-path rows on the current docs home any authored section landing doc can drive grouped section-level next-step rows and the section preview links shown on the current docs home Authors can now supply that metadata in either of two places: Inline Markdown front matter at the top of the .md file A paired sidecar YAML file such as README.md.yml or README.md.yaml Inline front matter remains the default authoring path for ordinary docs pages. Paired sidecars are the recommended escape hatch for portability-sensitive files such as README.md , where raw front matter renders poorly on GitHub and other plain Markdown surfaces. yaml # README.md.yml title: AppSurface summary: Follow the proof paths that explain what this framework is for and how it composes. featured_page_groups: - intent: understand label: Understand the model summary: Start here when you need the mental model before choosing an implementation path. order: 10 pages: - question: How does composition work? path: guides/composition.md supporting_copy: Start with the composition guide before drilling into APIs. order: 10 - label: See it working order: 20 pages: - question: Show me an end-to-end example path: examples/hello-world/README.md order: 10 Field behavior intent is the stable group identity. If omitted, RazorDocs derives one from label . label is the reader-facing group heading. If omitted, RazorDocs title-cases intent . summary explains when a reader should choose the group. order is optional on groups and pages. Lower values sort first, and ties preserve authored order. pages must contain the featured destinations for the group. Empty page lists are skipped. question is the reader-facing label shown on a row. If omitted, RazorDocs falls back to the destination page title. path accepts either the source path or canonical docs path for the destination page, including an exact #fragment suffix when the card should land on a specific section. RazorDocs normalizes forward-slash and backslash separators during resolution while preserving fragment identifiers, and the same resolver used by page details handles the configured live docs root. supporting_copy is optional landing-only text. If omitted, RazorDocs falls back to the destination page summary. Author three to five groups for a broad landing page, and one to three pages per group. Prefer plain reader intents such as understand , choose-package , see-it-working , release-risk , and api-reference . Use custom intents when your product has domain-specific decisions that those defaults do not capture. Preview locally from the repository root with the standalone docs host: Bash dotnet run --project Web/ForgeTrust.AppSurface.Docs.Standalone -- --urls http://localhost:5189 Or use the AppSurface CLI shape, which keeps RazorDocs workflows under the appsurface command family: Bash dotnet run --project Cli/ForgeTrust.AppSurface.Cli -- docs --repo . --urls http://localhost:5189 Then open the configured docs home, http://localhost:5189/docs by default. The standalone host remains the reusable runtime seam; appsurface docs is the public CLI entry point for the same preview workflow rather than a separate razordocs tool. Fallback and visibility rules If the root README.md is missing, the landing stays on the neutral docs index. If featured_page_groups is missing, the landing uses the neutral docs index unless the Start Here public section can provide the built-in proof-path fallback. If featured_page_groups: [] is authored inline, the explicit empty list is authoritative and suppresses sidecar fallback. If both README.md.yml and README.md.yaml exist for the same Markdown file, RazorDocs logs a warning and ignores both sidecars until the conflict is removed. If both sidecar metadata and inline front matter define the same field, inline front matter wins and the sidecar acts as fallback metadata only. Invalid sidecar YAML logs a warning and falls back to the inline/default metadata path instead of breaking the page harvest. If a featured path is missing, hidden from public navigation, or duplicated, RazorDocs skips it and logs a warning. If all featured entries are skipped, RazorDocs logs one final warning and falls back instead of rendering broken rows. The old flat featured_pages field is ignored and logs a migration warning. If both fields are present, featured_page_groups wins. Diagnostics include the source file, field path when available, problem, cause, and fix. Common warnings are stale featured_pages , missing group identity, missing or null pages , flat-looking group entries, blank path , missing destination, hidden destination, duplicate destination, invalid YAML, sidecar extension conflicts, and all groups skipped after resolution. Pitfalls Do not create both .yml and .yaml sidecars for the same Markdown file. RazorDocs treats that as an authoring error and ignores both. Do not use a sidecar as a second secret metadata system. It supports the same DocMetadata schema as inline front matter, and it is best reserved for files whose Markdown needs to stay portable on other surfaces. Do not put path or question directly under a group. Page fields belong under pages . Prefer source-relative paths for authored curation when the docs may be exported or mounted under more than one route. Canonical docs-surface paths are accepted for parity with browser links, but source paths stay easier to review and move with the file. README portability matters most at the repository and package level. In this repo, authored README.md files should stay free of inline front matter so GitHub renders them cleanly. Metadata-Driven Wayfinding RazorDocs can render two kinds of page-local wayfinding on details pages without scraping rendered HTML after the fact: On this page links come from the harvested DocNode.Outline contract. Previous and Next proof-path links come from explicit metadata, not folder inference. Page-local outline behavior On this page is local navigation for the current detail page. It intentionally does not mirror the left sidebar, which remains global documentation navigation. This keeps the two maps separate: the sidebar answers \u0022where am I in the docs product?\u0022 while the outline answers \u0022where am I on this page?\u0022 When DocDetailsViewModel.HasOutline is true, RazorDocs renders one semantic outline nav: wide desktop ( \u003E=1280px ): a sticky right rail beside the article narrower viewports: a closed-by-default On this page toggle above the article all viewports: the same outline list, never separate desktop and mobile TOCs The outline client enhances the server-rendered links by: using #main-content as the scroll root for IntersectionObserver marking the current section with aria-current=\u0022location\u0022 refreshing the active section from the scroll position on scroll, throttled through requestAnimationFrame , so long sections do not stay pinned to the previous outline item until the next heading enters the observer band keeping the active outline link visible inside the sticky desktop rail when the page-local outline is taller than the viewport easing outline-link clicks to the target section over 620 ms, while preserving instant jumps for readers who prefer reduced motion and canceling the animation when the reader manually wheels or touches the scroll root initializing from the current URL hash rebinding after RazorWire/Turbo frame navigation replaces rw:island id=\u0022doc-content\u0022 containing scroll inside the expanded compact outline so touch or wheel input over On this page does not move the article behind it collapsing the mobile outline after an outline link is chosen skipping missing heading targets for active-state tracking while leaving their normal hash links intact instead of marking stale entries current or closing the drawer If JavaScript is unavailable, the server-rendered outline remains a normal list of hash links. If IntersectionObserver is unavailable, RazorDocs keeps static and hash-based behavior rather than adding a scroll polling fallback. Sequence contract Use sequence_key together with order when a set of pages should behave like one proof path: yaml sequence_key: razorwire-proof order: 20 related_pages: - Web/ForgeTrust.RazorWire/README.md - Web/ForgeTrust.RazorWire/Docs/antiforgery.md sequence_key opts a page into a specific sequence. Pages do not join a sequence just because they share a folder. order determines the relative previous/next position inside that sequence. related_pages stays independent from sequencing and can point to source paths, canonical docs paths, or exact page titles. RazorDocs publishes authored sequence metadata to the current-surface search index for custom clients and integrations. The live source surface emits that payload at {DocsRootPath}/search-index.json (for example, /docs/search-index.json by default when versioning is off, /docs/next/search-index.json by default when versioning is on, or /foo/bar/search-index.json for a custom unversioned route root); exported exact-version trees carry their own search-index.json payload at the tree root. The sequence_key front-matter value becomes sequenceKey , order stays order , and related_pages stays separate as relatedPages ; for example: { \u0022sequenceKey\u0022: \u0022razorwire-proof\u0022, \u0022order\u0022: 20, \u0022relatedPages\u0022: [\u0022Web/ForgeTrust.RazorWire/README.md\u0022] } . Resolution rules Previous/next links render only when the current page has both sequence_key and order . RazorDocs only sequences navigable pages. Fragment-only anchor stubs and pages hidden from public navigation do not appear in proof-path navigation. Related pages are deduplicated against the current page and any resolved previous/next neighbors. Pitfalls Do not rely on filename prefixes or folder adjacency for proof-path behavior in this slice. Use explicit sequence_key values instead. Do not expect related_pages to imply ordering. Related links stay unordered beyond the authored list order. Metadata-Driven Page Type Display RazorDocs treats page_type metadata as structured UI input, not just as opaque search metadata. The built-in landing cards, detail pages, and search results all normalize the same metadata through DocMetadataPresentation.ResolvePageTypeBadge() . Built-in normalization Known values such as guide , example , api-reference , internals , how-to , start-here , troubleshooting , glossary , faq , and release render with stable labels and intentional badge variants. Release aliases release-note and release-notes render as the canonical Release badge with the normalized release value and variant. Unknown values still render safely: RazorDocs normalizes whitespace, underscores, and dashes, then falls back to a neutral title-cased badge. Missing or blank page_type values render no badge at all instead of leaving empty chrome behind. Search payload contract The current-surface search-index.json payload continues to emit the raw pageType metadata value and now also includes: pageTypeLabel for the normalized display label used by the built-in search UI pageTypeVariant for the built-in badge variant suffix used by CSS classes such as docs-page-badge--guide publicSection for the normalized built-in section slug when the page is publicly visible publicSectionLabel for the reader-facing section label isSectionLanding for authored section landing entry points These fields let custom search clients stay visually aligned with the landing and detail experiences without re-implementing the mapping table. When authored metadata uses release-note or release-notes , RazorDocs keeps the raw pageType metadata value in the payload but emits pageTypeLabel = \u0022Release\u0022 and pageTypeVariant = \u0022release\u0022 so built-in and custom clients can present release pages consistently. Custom Harvester Outline Contract The built-in Markdown and C# harvesters now populate DocNode.Outline directly during harvest. Custom IDocHarvester implementations should do the same when they want: On this page links on details views heading metadata in the current-surface search-index.json stable behavior without re-parsing rendered HTML later Each outline entry should provide the rendered fragment Id , the reader-facing Title , and the normalized heading Level . For visual parity with the built-in wayfinding UI, custom IDocHarvester implementations should populate DocNode.Outline only with entries that have a non-empty rendered fragment Id and non-empty Title ; headings or generated sections missing either value are skipped by the built-ins. The Markdown harvester emits source-ordered H2-H3 headings by default, with titles normalized from inline heading text and IDs taken from the rendered heading fragment. The C# harvester emits level 2 entries for documented types and enums, and level 3 entries for method groups and properties. Matching those defaults keeps custom outlines aligned with the built-in On this page rail, active-section behavior, and search heading metadata. Public visibility note: HideFromSearch = true removes a page from the search payload directly. HideFromPublicNav = true also removes the page from the search payload because the public shell treats hidden pages as fully non-public. Default path exclusions run before metadata is assigned. Test-project README files and C# source under test-project directories are not harvested, and C# source under examples is skipped so generated API-reference pages for example apps do not enter navigation, search, or direct docs routing. Trust Metadata For Release Notes And Policy Pages RazorDocs can also render a top-of-page trust bar from nested trust metadata. AppSurface uses this for its own release notes, upgrade policy, and changelog pages so the product doubles as a working example for consumers. yaml trust: status: Unreleased summary: This page is provisional until the next tag is cut. freshness: Updated as changes land on main. change_scope: Repository-wide. migration: label: Read the upgrade policy href: /docs/releases/upgrade-policy archive: Tagged release notes will keep the final narrative once the version ships. sources: - CHANGELOG.md - releases/unreleased.md Field behavior status is the compact top-level state, such as Unreleased or Pre-1.0 policy . summary is the short trust statement shown beside the status. freshness explains how current the page is and how stable readers should assume it is. change_scope calls out which surfaces the note covers. migration is an optional label plus browser-facing href to the adoption guidance. archive explains where the durable tagged record or long-term home lives. sources is an optional list of provenance notes or upstream artifacts. Merge behavior Inline front matter and sidecar YAML both use the same nested trust schema. Inline metadata wins over sidecar metadata field by field. Explicit empty lists such as sources: [] are authoritative and suppress fallback lists. Pitfalls Use a browser-facing href for migration , not a source path, because the trust bar renders a plain link without path rewriting. Keep private maintainer-only runbooks outside harvested docs. Hidden pages are removed from nav and search, but they are still public if linked directly. Do not turn the trust bar into marketing chrome. It should answer status, safety, and provenance questions quickly. Related Projects ForgeTrust.AppSurface.Docs.Standalone for the exportable host used in docs export and smoke testing Back to Web List Back to Root Notes This package is the reusable documentation surface; ForgeTrust.AppSurface.Docs.Standalone is the thin executable wrapper used for local hosting and export scenarios. The bundled RazorDocs UI includes its generated stylesheet and docs runtime files as static web assets and assembly-embedded fallback resources. The layout resolves the correct stylesheet path automatically from the host\u0027s root module shape for standalone/root-module hosts versus embedded application-part consumers, while endpoint fallbacks keep packaged hosts working when static web asset manifests are unavailable. Consumers do not need to call services.AddTailwind() unless they also want Tailwind build/watch integration for their own host application\u0027s CSS. It depends on the Tailwind package family for RazorDocs package build-time styling generation and on the caching package for docs aggregation performance.","snippet":"ForgeTrust.AppSurface.Docs Documentation site generation and hosting for AppSurface web applications. Overview ForgeTrust.AppSurface.Docs is the reusable Razor Class Library package behind the RazorDocs experience. It...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Docs"],"sourcePath":"Web/ForgeTrust.AppSurface.Docs/README.md"},{"id":"web/forgetrust.appsurface.docs.standalone","path":"/docs/web/forgetrust.appsurface.docs.standalone","title":"ForgeTrust.AppSurface.Docs.Standalone","summary":"AppSurface host for serving or exporting RazorDocs as an application.","headings":["What it is for","Entry Point","Strict Harvest Failure","Local URL Behavior","Contributor Provenance Smoke Testing","Related Projects"],"bodyText":"ForgeTrust.AppSurface.Docs.Standalone AppSurface host for serving or exporting RazorDocs as an application. What it is for This project is the thin executable wrapper around the reusable ForgeTrust.AppSurface.Docs package. It exists so the docs surface can run as: a local standalone site during development the export target in CI a smoke-testable host that proves the package seam stays honest For public command-line workflows, use the AppSurface CLI as the public command surface: Bash dotnet run --project Cli/ForgeTrust.AppSurface.Cli -- docs --repo . --urls http://127.0.0.1:5189 The CLI delegates to this standalone host, so the host remains the source of truth for RazorDocs startup, static web assets, routes, and configuration binding. Entry Point The app boots through Program.cs , which delegates to RazorDocsStandaloneHost . RazorDocsStandaloneHost is the reusable host entry point for this executable: RunAsync(string[] args) starts the standalone app and is what Program.cs uses. CreateBuilder(string[] args, IEnvironmentProvider? environmentProvider = null) returns an IHostBuilder without starting it. CreateBuilder(string[] args, IEnvironmentProvider? environmentProvider, Action\u003CWebOptions\u003E? configureOptions) adds the same builder seam plus web-option customization for package-hosted tools. Use CreateBuilder when a test or tool needs the real standalone host in-process. It keeps the same RazorDocsWebModule , MVC routes, static web assets, and RazorDocs configuration binding as the executable path while avoiding a shell-out to dotnet run . Do not duplicate standalone setup in test fixtures. If a scenario needs different URLs, repository roots, contributor templates, or environment behavior, pass those through command-line configuration or the optional environment provider so the normal host builder still owns the app shape. CreateBuilder is lower level than RunAsync : callers that build and start the host themselves should pass --urls , --port , or configure the web host before Build() instead of relying on the executable startup path\u0027s development-port fallback. The builder pins this standalone assembly as the host entry point identity so in-process callers, including xUnit, resolve the same static web asset manifest as the executable. The optional configureOptions callback is for host-shape seams that must stay on the normal AppSurface Web path. appsurface docs uses it to disable static web asset manifest loading for packaged tool runs because RazorDocs and RazorWire runtime assets are embedded in their assemblies. The shared AppSurface Web startup watchdog still applies through WebOptions.StartupTimeout , which defaults to 30 seconds and fails fast when the process stalls before Kestrel starts listening. Strict Harvest Failure Use RazorDocs:Harvest:FailOnFailure=true when the standalone host is acting as an export or CI publish target and an all-failed harvest should stop the run before the app starts listening. Bash RazorDocs__Harvest__FailOnFailure=true \\ dotnet run --project Web/ForgeTrust.AppSurface.Docs.Standalone -- --urls http://127.0.0.1:5189 Strict mode fails only when every configured harvester fails, times out, or cancels. Empty docs and partially degraded docs still start. The thrown RazorDocsHarvestFailedException uses a redacted summary suitable for CI output; raw exception details and repository paths remain in host logs for operators. Local URL Behavior When you run this host in Development without explicit endpoint configuration, AppSurface Web assigns a deterministic localhost-only development URL from the current workspace path. That keeps sibling worktrees from colliding on the same default localhost URL. The standalone host redirects / to the configured RazorDocs home, /docs by default. The reusable RazorDocs package keeps embedded apps isolated to their configured docs routes; this root redirect exists only because this executable is a docs-only host and CI export target. Use the startup log as the source of truth for the selected local URL. Pass --port 5189 , --urls http://127.0.0.1:5189 , ASPNETCORE_HTTP_PORTS=5189 , or a Kestrel:Endpoints appsettings/environment entry when you intentionally want a fixed address. The checked-in launch profile no longer pins a single shared localhost port, because that was the source of cross-worktree QA confusion. Contributor Provenance Smoke Testing The standalone host does not ship a checked-in source or edit target. Hard-coding a public repository or branch in the executable host would make feature-branch and fork smoke tests point readers at the wrong revision. If you want the live standalone host to exercise the full Source of truth strip, provide RazorDocs:Contributor explicitly in the environment or app settings that launch the host: JSON { \u0022 RazorDocs \u0022 : { \u0022 Contributor \u0022 : { \u0022 Enabled \u0022 : true , \u0022 DefaultBranch \u0022 : \u0022 feature/issue-143 \u0022 , \u0022 SourceUrlTemplate \u0022 : \u0022 https://github.com/owner/repo/blob/{branch}/{path} \u0022 , \u0022 EditUrlTemplate \u0022 : \u0022 https://github.com/owner/repo/edit/{branch}/{path} \u0022 , \u0022 LastUpdatedMode \u0022 : \u0022 Git \u0022 } } } Set DefaultBranch and the repository templates to the exact repo and ref you want readers to reach. Slash-separated refs such as feature/issue-143 are preserved in the generated GitHub-style URLs while still escaping special characters inside each segment. For local forks or branch previews, do not reuse upstream main unless that is truly the page\u0027s source of truth. Set LastUpdatedMode to Git when you want the standalone host to exercise relative freshness too. The package default is None , so git-backed timestamps stay opt-in. If you cannot provide a trustworthy source or edit destination, leave the templates unset. RazorDocs will still omit unsafe links instead of guessing, and it will omit git-backed Last updated unless you explicitly opt into git freshness. Page-level last_updated_override metadata can still supply an explicit timestamp. The Playwright integration suite starts this standalone host in-process with explicit contributor settings so this runtime configuration seam stays covered. It intentionally does not run dotnet run from the fixture; focused test runs should build and host the current project source directly instead of reusing stale standalone bin output. Related Projects ForgeTrust.AppSurface.Docs for the reusable docs package Back to Web List Back to Root","snippet":"ForgeTrust.AppSurface.Docs.Standalone AppSurface host for serving or exporting RazorDocs as an application. What it is for This project is the thin executable wrapper around the reusable ForgeTrust.AppSurface.Docs...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Docs.Standalone"],"sourcePath":"Web/ForgeTrust.AppSurface.Docs.Standalone/README.md"},{"id":"web/forgetrust.appsurface.docs/design","path":"/docs/web/forgetrust.appsurface.docs/design","title":"RazorDocs Design Language","summary":"RazorDocs should feel like a focused documentation workspace, not a marketing site and not a generic SaaS dashboard. The UI should help people orient quickly, scan densely, and move deeper into docs with very little friction.","headings":["Purpose","Core Tone","Visual System","Typography","Color","Style Tokens","Surfaces","Styling Boundary","Default Rule","Why Ownership Beats Style Purity","Edge Cases","Anti-Patterns","Review Questions","Search Workspace","Starter State","Results","Filters","State Design","Page-Local Navigation","Interaction Rules","Accessibility"],"bodyText":"RazorDocs Design Language Purpose RazorDocs should feel like a focused documentation workspace, not a marketing site and not a generic SaaS dashboard. The UI should help people orient quickly, scan densely, and move deeper into docs with very little friction. Core Tone Quietly technical Editorial rather than card-heavy Dense, but never cramped Confident without looking flashy If a new surface starts to feel like a feature grid, a landing page, or an AI-generated admin template, pull it back. Visual System Typography Primary typeface: Outfit Body copy should stay clean and readable with generous line-height Authored Markdown prose should use a shorter measure and stronger paragraph/list rhythm than generated API reference pages. Release notes and long guides must scan as editorial documents, not as one uninterrupted text column. Headings should feel compact and intentional, not oversized hero copy Search results should privilege readable title hierarchy over decorative framing Color Base surfaces: dark slate family Accent: cyan for focus, active state, and high-value calls to action Borders and separators should do most of the structure work Avoid adding extra accent colors unless the feature truly needs semantic differentiation Style Tokens RazorDocs expresses the flagship dark-slate system through internal --docs-* CSS custom properties in wwwroot/css/app.css . The token layer exists so contributors can preserve the same visual language without rediscovering which hardcoded slate, cyan, or translucent fill belongs to each shared primitive. Token names should describe the design job: surface, border, text, accent, focus, active state, code chrome, table chrome, or skeleton. Do not name tokens after Tailwind hues unless the hue itself is the contract, which it usually is not. Default rule: If a color or treatment appears across unrelated shared selector groups, use or add a token. If a color represents a repeated state such as focus, active, muted, raised, loading, or default border, use or add a token. If a color is local to syntax highlighting, generated API signature colorization, or a one-off semantic badge family, keep it local and document the category. These tokens are not a public theming API yet. Hosts should not rely on overriding --docs-* names until a future theming feature explicitly documents that contract. Inside RazorDocs, though, shared package chrome and search-specific UI should consume the same root token layer so future theming can change the system deliberately. Search CSS may route through --docs-search-* aliases with fallbacks because exact published release trees can serve search.css without the generated package stylesheet. Surfaces Prefer layered panels, separators, and subtle fills over heavy boxed cards Result lists should read like an editorial index with strong rows, not isolated product cards Keep shadows minimal; contrast and spacing should carry the layout Styling Boundary RazorDocs uses multiple styling patterns because it is solving different ownership and stability problems. Owned package chrome is local product UI. Harvested content is nested document output. Stateful search UI also needs selectors that both CSS and JavaScript can trust. Treating those surfaces as one blanket styling problem is how teams end up arguing about style purity instead of making the interface easier to maintain. Default Rule Use this order when deciding where a new style belongs: Reusable component contract or shared CSS and JavaScript hook: semantic class. Unowned nested content rendered inside a package wrapper: wrapper-scoped semantic CSS. One-off package chrome that RazorDocs owns directly: Tailwind utilities in markup. README.md is the fast rulebook for this decision. This document explains why the rule exists and where contributors usually get tripped up. Why Ownership Beats Style Purity One-off owned chrome is easiest to read when the intent stays in the Razor markup that owns it. Harvested content is safest to style through a wrapper such as .docs-content because RazorDocs does not control each nested node or authoring shape. Markdown and generated API reference are both harvested content, but they are different reading jobs. Use .docs-content--markdown for prose rhythm and keep .docs-content--api on the wider base reference treatment. Reusable package components deserve semantic names even when RazorDocs owns the markup, because repeated UI contracts are easier to review and update when they have one stable selector. Search surfaces need semantic hooks because the stylesheet and search-client.js both rely on the same stable names across loading, empty, failure, and active-filter states. Edge Cases Reusable owned package UI Classes such as docs-page-badge and docs-metadata-chip are not a failure of utility-first styling. They are the right tool when a repeated package component needs one stable contract across multiple views and stylesheets. Shared reusable primitives belong in the Tailwind entry stylesheet at wwwroot/css/app.css , which generates the package stylesheet loaded on every RazorDocs page. Search-specific state and result styling belongs in wwwroot/docs/search.css ; do not make non-search pages depend on search assets for badges, metadata chips, or trust/provenance chrome. Search workspace hooks The search workspace renders semantic classes such as docs-search-page , docs-search-page-filters-toggle , and docs-search-page-active-filters directly in Razor, then extends those hooks in CSS and JavaScript. That is intentional. Shared hooks keep stateful UI readable and stable. That does not mean every heading, paragraph, or fallback-link wrapper inside Search.cshtml needs its own semantic class. Keep the stateful container and interactive hook semantic, then use local utilities for one-off typography and spacing inside that single view. Required id values Some search controls still need unique id values such as docs-search-page-input and docs-search-page-filters-panel . Those support uniqueness, accessibility relationships, and DOM targeting. They do not replace semantic classes as the reusable styling contract. Anti-Patterns Avoid these by default: adding semantic classes to static package chrome when local utilities are clearer forcing repeated package UI back into long utility strings when a shared component class is already the simpler contract pushing utility classes into harvested nested HTML that RazorDocs does not fully own treating shared CSS and JavaScript hook classes as a failure of Tailwind instead of a legitimate integration seam moving styles across the boundary without a concrete user-facing benefit Review Questions When reviewing a change, ask: Does this surface need a reusable selector that more than one file depends on? Does RazorDocs fully own this markup, or is it styling nested harvested content? Will a future contributor understand where the style belongs without reading half the package? Is this change improving usability or maintainability, or just chasing stylistic consistency? Search Workspace /docs/search is a search-first workspace. Keep the primary search input visually dominant Place filters directly under or adjacent to the query area Keep one main results stream, ranked by relevance Use badges and breadcrumbs to add context without fragmenting the scan path Starter State The empty state should guide without feeling promotional. Include a one-sentence orientation Show clickable suggestion chips Explain that filters can also be used for browse mode before typing Show representative starter rows after the index loads so the page proves the corpus shape before the user knows the exact query Treat starter rows as discovery aids in the same single editorial stream, not as grouped dashboard columns Omit missing representative page types cleanly; do not render empty placeholders for Guide, API Reference, Example, Troubleshooting, or Release when the corpus lacks one Results Results should be a high-information list. Title is the strongest element Breadcrumbs come first and stay subtle Badges are compact metadata, not visual decoration Snippets should stay short and readable Highlight matches with restrained \u003Cmark\u003E styling Blank snippets should be omitted instead of replaced with filler text Page-type badges should use the shared badge vocabulary, including Release for release-note metadata aliases Filters Desktop: filters are visible within the page workspace Mobile: collapse filters behind a compact toggle with active-filter summary pills Disabled zero-result options should remain visible so the dataset shape stays legible State Design Search has distinct states and they should look distinct. First load: show skeleton rows and clear \u201CLoading search index...\u201D messaging Refinement updates: keep prior results visible and use a subtle busy state No results: explain that the search worked, then offer recovery paths Failure: explain that search itself is unavailable, show retry, and provide fallback links Do not reuse the no-results treatment for actual failures. Page-Local Navigation On this page is a local map for the current document, not a second global navigation surface. The left sidebar owns the docs product hierarchy. The page outline owns the reader\u0027s position inside the current article. Desktop details pages with an outline should use an article-first composition: page title and current article content quiet page-local outline rail active section marker visible enough to scan without competing with reading The persistent rail appears only on wide desktop ( \u003E=1280px ) so the article column stays readable. Below that breakpoint, use one sticky collapsed On this page control above the article. Do not render separate desktop and mobile outlines. Visual rules: Keep the rail editorial and quiet: border/separator structure beats boxed cards. Use cyan for active and focus states only. Borrow the active-row treatment from the approved mockup direction: subtle row fill plus a cyan marker. Keep H2 links stronger and H3 links quieter/indented. Use small row radii only. Do not wrap the whole rail in a large rounded card. Preserve the existing RazorDocs global sidebar; do not replace it with icon-only chrome for this pattern. On compact viewports, the collapsed outline may show previous, current, and next section context. The current section is dominant; previous and next stay smaller and quieter so the control remains a reader aid instead of a second header. When the compact outline is expanded, it is a bounded scroll surface with contained overscroll. Readers should be able to inspect a long On this page list without accidentally moving the article behind it. Interaction rules: The active outline link uses aria-current=\u0022location\u0022 . Mobile outline links collapse the outline after navigation so the reader returns to content. Compact context rows can use a subtle vertical rolling cue when the active section changes. Animate text rows only, keep the shell fixed-height, and disable the cue under prefers-reduced-motion: reduce . JavaScript enhances server-rendered hash links. It must not create a hidden-only outline when scripts fail. Interaction Rules / focuses the visible search input when the user is not already typing Cmd/Ctrl\u002BK opens the search workspace or focuses the advanced input Browser history should feel natural: typing updates URL state with replace semantics deliberate filter changes create navigable history entries Back/Forward must restore query, filters, and rendered results Accessibility Preserve semantic headings, labels, and live regions for status changes Loading, failure, and no-results states must remain understandable without visual context Focus should move predictably for shortcuts, retry, and suggestion chips Mobile layouts should keep search and results visible without forcing long filter scrolls Anti-Patterns Avoid these by default: chunky boxed result cards oversized marketing hero treatments decorative gradients inside core reading surfaces multiple competing result columns hiding the corpus shape behind over-minimal filter UI introducing visual styles that do not already fit the dark-slate plus cyan system","snippet":"RazorDocs Design Language Purpose RazorDocs should feel like a focused documentation workspace, not a marketing site and not a generic SaaS dashboard. The UI should help people orient quickly, scan densely, and move...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","RazorDocs Design Language"],"sourcePath":"Web/ForgeTrust.AppSurface.Docs/DESIGN.md"},{"id":"web/forgetrust.appsurface.docs/roadmap","path":"/docs/web/forgetrust.appsurface.docs/roadmap","title":"RazorDocs Roadmap","summary":"This note keeps the in-repo RazorDocs plan aligned with the phased GitHub roadmap.","headings":["Product Direction","Phase 1: Metadata Foundation","Phase 2: Evaluator Experience","Phase 3: Platform Breadth, Relevance, and Telemetry","Notes"],"bodyText":"RazorDocs Roadmap This note keeps the in-repo RazorDocs plan aligned with the phased GitHub roadmap. Product Direction RazorDocs is being shaped as a .NET -native documentation framework for libraries and frameworks that unifies authored guides, examples, and source-derived API reference in one experience for human and agentic readers. AppSurface is the first flagship consumer of this work. The initial phases should make AppSurface\u0027s documentation more trustworthy for evaluators while also proving the reusable RazorDocs product surface. Phase 1: Metadata Foundation Status: shipped Phase 1 focused on the shared metadata and indexing layer: front matter and structured doc metadata metadata defaults for markdown and harvested API docs namespace README merging metadata-backed search payloads metadata-aware navigation and breadcrumb behavior This phase creates the foundation for later landing-page, search, and wayfinding work without hardcoding repo-specific behavior into views. Phase 2: Evaluator Experience GitHub milestone: RazorDocs Phase 2: Evaluator Experience Phase 2 is the first visible product slice built on top of the metadata foundation. The goal is to help an evaluating engineer answer trust questions quickly and move from high-level orientation into concrete examples and API details while also closing the baseline platform gaps that keep RazorDocs from feeling competitive as a serious docs product. This phase should now ship in four moves: turn the root docs landing into a metadata-driven trust-routing surface extend the same curation and landing pattern to section or pillar entry points such as Start Here , Examples , and Troubleshooting add the core docs-platform capabilities evaluators and maintainers expect, including versioning, contributor workflow affordances, canonical routes, and locale support keep the resulting experience legible in navigation and search instead of bolting those capabilities on as isolated admin features Primary issues: #101 Rebuild public docs navigation around user intent #102 Add canonical doc slugs with legacy-safe redirects #106 Redesign docs search UI with filters and richer results #107 Create Start Here, troubleshooting, and glossary content foundations #109 Add deep-page wayfinding with TOC, related links, and next steps #123 Add evaluator-first docs landing with featured proof paths #124 Render metadata-driven page type badges across landing, details, and search #125 Add featured page curation for evaluator questions #126 Add a concise RazorDocs product explainer to the flagship docs experience #142 Add docs versioning with version-aware navigation and search #143 Add contributor workflow features like edit links and last-updated metadata #144 Add i18n with locale-aware routing and search Recommended shipping emphasis: featured page curation evaluator-first landing versioning plus version-aware navigation and search deep-page wayfinding contributor workflow affordances plus canonical routes locale-aware docs routing and search section and pillar landing follow-through using the same metadata contract concise RazorDocs product explainer Phase 3: Platform Breadth, Relevance, and Telemetry GitHub milestone: RazorDocs Phase 3: Platform Breadth, Relevance, and Telemetry Phase 3 deepens the platform breadth after the evaluator-facing experience is visible. The goal is to improve search intelligence and telemetry while also expanding RazorDocs into a more complete documentation framework with adjacent content types, richer authoring, and explicit extension and deployment seams. Primary issues: #104 Expand search index with metadata and visibility controls #105 Tune search ranking for intent-based relevance #108 Add config-gated search telemetry and docs metrics #145 Add docs-adjacent content types for release notes, blog, and standalone pages #146 Add extension surfaces and production docs platform plumbing #147 Add richer authoring primitives for interactive technical docs Notes These phases are intended to be additive. Phase 2 should consume the Phase 1 foundation rather than reworking it. Phase 1 made the metadata pipeline page-agnostic on purpose. Phase 2 should first consume that seam from the repo-root README.md , then reuse it for non-root landing pages without introducing a parallel content system. AppSurface remains the first proof site, but the roadmap should favor reusable RazorDocs capabilities over one-off customizations. Future RazorDocs styling work should follow the package-level styling boundary contract documented in README.md and explained in DESIGN.md , rather than reopening Tailwind-versus-semantic-CSS debates from scratch. Future phases can expand into more explicit agent-facing features once the evaluator experience and search relevance are working well.","snippet":"RazorDocs Roadmap This note keeps the in-repo RazorDocs plan aligned with the phased GitHub roadmap. Product Direction RazorDocs is being shaped as a .NET -native documentation framework for libraries and frameworks...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","RazorDocs Roadmap"],"sourcePath":"Web/ForgeTrust.AppSurface.Docs/ROADMAP.md"},{"id":"web/forgetrust.appsurface.docs/use-razordocs","path":"/docs/web/forgetrust.appsurface.docs/use-razordocs","title":"Use RazorDocs in your repository","summary":"Learn when to adopt RazorDocs, how to host it, and how to use authored metadata to turn repository Markdown and C# APIs into a usable docs site.","headings":["When to use it","The consumer model","Fastest path","Author the first useful page set","Curate the landing page","Add reference and proof over time","Adoption checklist","Where to go next"],"bodyText":"Use RazorDocs in your repository RazorDocs is the documentation surface for a repository that wants authored guidance, working examples, and source-derived API reference in one place. It is not a separate content management system. It reads the docs and code you already keep with the product, then serves them through a navigable ASP.NET Core experience. AppSurface is the first proof site. The public docs you are reading are harvested from this repository, grouped with RazorDocs metadata, searched with the built-in search index, and published from the same package a consumer can install. When to use it Use RazorDocs when your repository has more than API reference and less than a full documentation platform team. Good fits: A .NET library or app with package READMEs, examples, and XML-doc-commented APIs. A product repo where install, upgrade, release, and troubleshooting docs need to stay close to code. An internal platform where engineers need a searchable source-of-truth site instead of scattered Markdown links. A docs site that should prove the package it describes by dogfooding its own renderer. Poor fits: A marketing site where every section needs bespoke campaign design. A documentation source that does not live with code and does not benefit from generated API reference. A static artifact that must be edited by non-technical authors without touching Git. The consumer model RazorDocs has three moving parts: A host that runs RazorDocsWebModule or the standalone RazorDocs app. A source repository that contains Markdown pages, package READMEs, examples, and C# source. Metadata that tells RazorDocs how to group, feature, search, and explain those pages. The result is a docs surface with: section-first navigation such as Start Here, Examples, Releases, Troubleshooting, and API Reference source-derived C# API pages a search index that includes titles, summaries, headings, aliases, keywords, and page types optional trust bars for release notes, policies, and provenance-heavy pages optional Source of truth links back to the exact files readers should inspect or edit Fastest path For a dedicated docs host, reference ForgeTrust.AppSurface.Docs and run the module: C# await WebApp \u003C RazorDocsWebModule \u003E . RunAsync ( args ) ; Point the host at the repository you want to harvest: JSON { \u0022 RazorDocs \u0022 : { \u0022 Mode \u0022 : \u0022 Source \u0022 , \u0022 Source \u0022 : { \u0022 RepositoryRoot \u0022 : \u0022 /path/to/repo \u0022 } } } If RazorDocs:Source:RepositoryRoot is omitted, RazorDocs falls back to repository discovery from the app content root. That is convenient for local dogfooding, but production hosts should make the repository root explicit so the docs source is not guessed from deployment layout. Author the first useful page set Start with pages that answer adoption questions before you tune visuals: README.md for the repository-level entry point. packages/README.md or package-level READMEs for install choices. examples/.../README.md for exportable proof paths. releases/README.md , CHANGELOG.md , or upgrade-policy pages when release risk matters. Troubleshooting pages for the failure modes your users actually hit. Use sidecar metadata for portability-sensitive files such as README pages: yaml # README.md.yml title: My Product summary: Start here when you need to choose the right package and prove the first workflow. featured_page_groups: - intent: adopt label: Adopt the docs package summary: The shortest path from repository Markdown to a usable docs site. pages: - question: How do I host these docs? path: docs/hosting.md supporting_copy: Start with the host shape, then add metadata once the page renders. Use inline front matter for ordinary authored pages when GitHub rendering is not the primary surface: yaml --- title: Troubleshoot search indexing summary: Fix missing or stale search results in a RazorDocs host. page_type: troubleshooting nav_group: Troubleshooting aliases: - search index - missing results --- Curate the landing page RazorDocs does not require a bespoke homepage template for each repo. The root landing can be curated from metadata: Put featured_page_groups in README.md.yml . Group destinations by reader intent, not by folder structure. Link to real harvested pages by source path. Keep each row focused on the question the reader has in their head. The important part is that curation stays authored content. If the product story changes, edit Markdown or sidecar YAML. Do not fork DocsController to hardcode a new marketing panel. Add reference and proof over time Once the first pages render, improve the docs in layers: Add XML docs to public C# APIs so generated reference pages are useful. Add summary , page_type , nav_group , aliases , and keywords metadata to high-traffic pages. Add troubleshooting pages for the first support questions people ask. Add release notes and trust metadata when adoption depends on upgrade confidence. Add versioned published trees only after the live source-backed docs are useful. That order matters. A beautiful archive of weak docs is still weak docs. Adoption checklist Pick a host: embedded AppSurface web module or standalone RazorDocs app. Configure RazorDocs:Source:RepositoryRoot for the repository to harvest. Keep RazorDocs:Mode set to Source unless a later bundle-hosting slice changes that contract. Add sidecar metadata for repository and package README files. Feature the first consumer paths through featured_page_groups . Verify /docs , /docs/search , and /docs/search-index.json . Run the standalone host or export pipeline in CI before publishing a public docs surface. Where to go next RazorDocs package reference Standalone RazorDocs host Package chooser Release hub","snippet":"Use RazorDocs in your repository RazorDocs is the documentation surface for a repository that wants authored guidance, working examples, and source-derived API reference in one place. It is not a separate content...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":["RazorDocs adoption","repository docs","docs hosting","generated API reference"],"keywords":["RazorDocsWebModule","AddRazorDocs","featured_page_groups","repository root"],"status":null,"navGroup":"Start Here","publicSection":"start-here","publicSectionLabel":"Start Here","isSectionLanding":false,"order":60,"sequenceKey":null,"canonicalSlug":null,"relatedPages":["Web/ForgeTrust.AppSurface.Docs/README.md","Web/ForgeTrust.AppSurface.Docs.Standalone/README.md","packages/README.md"],"breadcrumbs":["Start Here","Use RazorDocs in your repository"],"sourcePath":"Web/ForgeTrust.AppSurface.Docs/use-razordocs.md"},{"id":"web/forgetrust.appsurface.web","path":"/docs/web/forgetrust.appsurface.web","title":"AppSurface Web","summary":"The **ForgeTrust.AppSurface.Web** package provides the bootstrapping logic for building ASP.NET Core applications using the AppSurface module system. It sits on top of the compilation concepts defined in \u0060ForgeTrust.AppSurface.Core\u0060.","headings":["Overview","Key Abstractions","WebApp","IAppSurfaceWebModule","WebStartup","Features","MVC and Controllers","CORS","Endpoint Routing","Browser Status Pages","Conventional Production 500 Pages","Configuration and Port Overrides","Startup Watchdog"],"bodyText":"AppSurface Web The ForgeTrust.AppSurface.Web package provides the bootstrapping logic for building ASP.NET Core applications using the AppSurface module system. It sits on top of the compilation concepts defined in ForgeTrust.AppSurface.Core . Overview The easiest way to get started is by using the WebApp static entry point. This provides a default setup that works for most applications. C# await WebApp \u003C MyRootModule \u003E . RunAsync ( args ) ; For more advanced use cases where you need to customize the startup lifecycle beyond what the options provide, you can extend WebStartup\u003CTModule\u003E . Key Abstractions WebApp The primary entry point for web applications. It handles creating the internal startup class and running the application. It provides a generic overload WebApp\u003CTModule\u003E for standard usage and WebApp\u003CTStartup, TModule\u003E if you have a custom startup class. IAppSurfaceWebModule Modules that want to participate in the web startup lifecycle should implement this interface. It extends IAppSurfaceHostModule and adds web-specific hooks: ConfigureWebOptions : Modify the global WebOptions (e.g., enable MVC, configure CORS). ConfigureWebApplication : Register middleware using IApplicationBuilder (e.g., app.UseAuthentication() ). ConfigureEndpoints : Map endpoints using IEndpointRouteBuilder (e.g., endpoints.MapGet(\u0022/\u0022, ...) ). WebStartup The base class for the application bootstrapping logic. While WebApp uses a generic version of this internally, you can extend it if you need deep customization of the host builder or service configuration logic. Features MVC and Controllers Support for MVC approaches can be configured via WebOptions : None : For pure Minimal APIs (default). Controllers : For Web APIs using controllers ( AddControllers ). ControllersWithViews : For traditional MVC apps with views. Full : Full MVC support. CORS Built-in support for CORS configuration: Enforced Origin Safety : When EnableCors is true, you MUST specify at least one origin in AllowedOrigins , unless running in Development with EnableAllOriginsInDevelopment enabled (the default). If AllowedOrigins is empty in production or when EnableAllOriginsInDevelopment is disabled, the application will throw a startup exception to prevent unintended security openness (verified by tests EmptyOrigins_WithEnableCors_ThrowsException and EnableAllOriginsInDevelopment_AllowsAnyOrigin ). Development Convenience : EnableAllOriginsInDevelopment (enabled by default) automatically allows any origin when the environment is Development , simplifying local testing without compromising production security. Default Policy : Configures a policy named \u0022DefaultCorsPolicy\u0022 (configurable) and automatically registers the CORS middleware. Endpoint Routing Modules can define their own endpoints, making it easy to slice features vertically (\u0022Vertical Slice Architecture\u0022). Browser Status Pages AppSurface Web includes conventional browser-facing pages for empty 401 , 403 , and 404 status responses. The feature is designed for human browser requests: it keeps the original HTTP status code, shows recovery-oriented HTML, and leaves JSON/API responses alone. Browser status pages in 2 minutes If your app already uses MVC views, keep the default Auto mode: C# public void ConfigureWebOptions ( StartupContext context , WebOptions options ) { options . Mvc = options . Mvc with { MvcSupportLevel = MvcSupport . ControllersWithViews } ; } If your app starts with controllers only but still wants the browser pages, opt in explicitly: C# public void ConfigureWebOptions ( StartupContext context , WebOptions options ) { options . Mvc = options . Mvc with { MvcSupportLevel = MvcSupport . Controllers } ; options . Errors . UseConventionalBrowserStatusPages ( ) ; } Preview the built-in pages while the app is running: Status Preview URL 401 /_appsurface/errors/401 403 /_appsurface/errors/403 404 /_appsurface/errors/404 Override any page with the conventional app or shared Razor Class Library path: Status Override path 401 ~/Views/Shared/401.cshtml 403 ~/Views/Shared/403.cshtml 404 ~/Views/Shared/404.cshtml Use BrowserStatusPageModel in overrides: Razor @ model ForgeTrust . AppSurface . Web . BrowserStatusPageModel \u003C h1 \u003E HTTP @ Model.StatusCode \u003C/ h1 \u003E \u003C p \u003E @ Model.OriginalPath \u003C/ p \u003E Mode behavior: Mode Behavior BrowserStatusPageMode.Auto Enables browser status pages only when MVC support already includes views. BrowserStatusPageMode.Enabled Always enables browser status pages and upgrades MVC support to controllers with views when needed. BrowserStatusPageMode.Disabled Leaves status-code handling fully to the app or other middleware. Important behavior: Only empty 401 , 403 , and 404 responses from GET or HEAD requests that accept text/html or application/xhtml\u002Bxml are re-executed. JSON, non-HTML, non-empty, and non-GET/HEAD responses keep their original API-friendly behavior. Missing default documentation 404 routes include a documentation search recovery link because stale docs links are the most common browser miss. The default RazorDocs route family is /docs , so the default recovery target is /docs/search . Apps that set RazorDocs:Routing:RouteRootPath should derive the search target from that root, for example RazorDocs:Routing:RouteRootPath=/foo/bar points stale-docs recovery links at /foo/bar/search . Static export remains conservative: RazorWire CLI probes /_appsurface/errors/404 and writes only 404.html ; it does not emit 401.html or 403.html . In CDN mode, that 404.html page is validated and rewritten with the rest of the static output. The fallback Return home link is marked data-rw-export-ignore so apps that do not export / can still publish a valid conventional 404.html . Production 500 exception pages are intentionally separate from browser status pages and must be enabled with UseConventionalExceptionPage() . Conventional Production 500 Pages AppSurface Web can also own a safe browser-facing production 500 page for unhandled exceptions. This is off by default because exception handling is usually application policy. Opt in through WebOptions.Errors.UseConventionalExceptionPage() when a normal MVC-style app wants a generic HTML failure page without writing exception middleware by hand. C# await WebApp \u003C MyRootModule \u003E . RunAsync ( args , options =\u003E options . Errors . UseConventionalExceptionPage ( ) ) ; The conventional exception page uses ASP.NET Core exception handling, not status-code pages. That distinction matters: status-code pages can render empty 404 or 500 responses, but they do not catch thrown exceptions. AppSurface registers the exception handler early enough to catch module middleware and endpoint failures, then renders a Razor view only for requests that accept text/html or application/xhtml\u002Bxml . The default view returns HTTP 500 , generic recovery copy, a home link, and a request id that operators can correlate with logs. The default ExceptionPageModel contains only StatusCode and RequestId ; it does not expose exception messages, stack traces, headers, cookies, route values, or form fields. Applications can override the page with ~/Views/Shared/500.cshtml . Keep the page generic and support-oriented. Do not read IExceptionHandlerFeature , request headers, cookies, route values, or form values unless the app has a deliberate reviewed disclosure policy. Development keeps its existing developer exception behavior. AppSurface does not install the conventional production handler when StartupContext.IsDevelopment is true. API-only apps, JSON problem-details APIs, tenant-specific error pages, or apps with telemetry-first exception middleware should leave this disabled and register their own exception handling. Once ASP.NET Core has started a response, exception handling cannot replace it with the conventional page. Design streaming endpoints so failures are reported through the stream protocol rather than relying on a late 500 page. Configuration and Port Overrides The web application supports standard ASP.NET Core configuration sources (command-line arguments, environment variables, and appsettings.json ). Deterministic Development Port Default When an AppSurface web application starts in Development without explicit endpoint configuration, AppSurface Web chooses a deterministic localhost-only fallback URL based on the current workspace path. That gives each local worktree a stable URL instead of every development environment fighting for the same hard-coded dev port. Use this default for local dotnet run convenience when you do not care about a specific port ahead of time. Override it any time with --port , --urls , ASPNETCORE_URLS / URLS , ASPNETCORE_HTTP_PORTS / DOTNET_HTTP_PORTS / HTTP_PORTS , ASPNETCORE_HTTPS_PORTS / DOTNET_HTTPS_PORTS / HTTPS_PORTS , urls / http_ports / https_ports in appsettings, or Kestrel:Endpoints in appsettings/environment variables. Treat the startup log as the source of truth for the selected local URL. The automatic fallback binds only http://localhost:{port} . Use --port or an explicit wildcard URL when you intentionally need LAN/container access. Port Overrides You can override the application\u0027s listening port using several methods: Command-Line : Use --port (shortcut) or --urls . Bash dotnet run -- --port 5001 # OR dotnet run -- --urls \u0022 http://localhost:5001 \u0022 Environment Variables : Set ASPNETCORE_URLS . Bash export ASPNETCORE_URLS= \u0022 http://localhost:5001 \u0022 dotnet run App Settings : Configure urls in appsettings.json . JSON { \u0022 urls \u0022 : \u0022 http://localhost:5001 \u0022 } Kestrel Endpoints : Configure named endpoints when you need protocol, certificate, or endpoint-specific settings. JSON { \u0022 Kestrel \u0022 : { \u0022 Endpoints \u0022 : { \u0022 Http \u0022 : { \u0022 Url \u0022 : \u0022 http://localhost:5001 \u0022 } } } } Note The --port flag is a convenience shortcut that maps to http://localhost:{port};http://*:{port} . This ensures the application is accessible on all interfaces while logging a clickable localhost URL in the console. If both --port and --urls are provided, --port takes precedence. [!TIP] If you rely on the deterministic development-port fallback, different worktrees on the same machine will get different stable ports. If you need a predictable shared URL for docs, QA, or CI instructions, pass --port or --urls explicitly instead of depending on the fallback. Startup Watchdog AppSurface Web fails fast when a host does not complete startup within WebOptions.StartupTimeout . The default is 30 seconds. This catches pre-bind stalls where the process is alive but Kestrel has not started listening, including sandbox restrictions, package layout issues, static web asset discovery hangs, and hosted services that block startup. Configure or disable the watchdog through WebOptions : C# await WebApp \u003C MyRootModule \u003E . RunAsync ( args , options =\u003E options . StartupTimeout = TimeSpan . FromSeconds ( 60 ) ) ; Set StartupTimeout to null only when the host intentionally performs long-running pre-bind work. Values at or below zero are invalid; use null instead of TimeSpan.Zero when disabling the guard. The watchdog stops checking once startup completes, so it does not limit normal request processing or long-running background work after the host is listening. \uD83D\uDCC2 Back to Web List | \uD83C\uDFE0 Back to Root","snippet":"AppSurface Web The ForgeTrust.AppSurface.Web package provides the bootstrapping logic for building ASP.NET Core applications using the AppSurface module system. It sits on top of the compilation concepts defined in...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","AppSurface Web"],"sourcePath":"Web/ForgeTrust.AppSurface.Web/README.md"},{"id":"web/forgetrust.appsurface.web.openapi","path":"/docs/web/forgetrust.appsurface.web.openapi","title":"ForgeTrust.AppSurface.Web.OpenApi","summary":"This package provides a modular integration for OpenAPI (Swagger) document generation in AppSurface web applications.","headings":["Overview","Usage","Features"],"bodyText":"ForgeTrust.AppSurface.Web.OpenApi This package provides a modular integration for OpenAPI (Swagger) document generation in AppSurface web applications. Overview The AppSurfaceWebOpenApiModule simplifies the configuration of OpenAPI by: Registering the necessary services via AddOpenApi . Configuring the EndpointsApiExplorer . Automatically mapping the OpenAPI documentation endpoints. Providing default document and operation transformers to clean up and brand the generated documentation based on the StartupContext . Usage To enable OpenAPI support in your application, add the AppSurfaceWebOpenApiModule as a dependency in your root module: C# public class MyModule : IAppSurfaceWebModule { public void RegisterDependentModules ( ModuleDependencyBuilder builder ) { builder . AddModule \u003C AppSurfaceWebOpenApiModule \u003E ( ) ; } // ... } Features Document Transformation : Automatically updates the API title and tags based on the application name defined in the StartupContext . Automatic Endpoint Mapping : Calls endpoints.MapOpenApi() for you during the endpoint configuration phase. \uD83D\uDCC2 Back to Web List | \uD83C\uDFE0 Back to Root","snippet":"ForgeTrust.AppSurface.Web.OpenApi This package provides a modular integration for OpenAPI (Swagger) document generation in AppSurface web applications. Overview The AppSurfaceWebOpenApiModule simplifies the...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Web.OpenApi"],"sourcePath":"Web/ForgeTrust.AppSurface.Web.OpenApi/README.md"},{"id":"web/forgetrust.appsurface.web.scalar","path":"/docs/web/forgetrust.appsurface.web.scalar","title":"ForgeTrust.AppSurface.Web.Scalar","summary":"This package integrates the [Scalar](https://scalar.com/) API Reference UI into AppSurface web applications.","headings":["Overview","Usage","Features"],"bodyText":"ForgeTrust.AppSurface.Web.Scalar This package integrates the Scalar API Reference UI into AppSurface web applications. Overview The AppSurfaceWebScalarModule provides a modern, interactive API documentation interface. It depends on ForgeTrust.AppSurface.Web.OpenApi and automatically configures everything needed to serve the Scalar UI. Usage Simply add the AppSurfaceWebScalarModule to your module dependencies: C# public class MyModule : IAppSurfaceWebModule { public void RegisterDependentModules ( ModuleDependencyBuilder builder ) { builder . AddModule \u003C AppSurfaceWebScalarModule \u003E ( ) ; } // ... } Features Built-in Dependency : Automatically registers the AppSurfaceWebOpenApiModule . Automatic UI Mapping : Maps the Scalar API reference endpoint using MapScalarApiReference() . Zero Config : Works out of the box with the default AppSurface startup pipeline. \uD83D\uDCC2 Back to Web List | \uD83C\uDFE0 Back to Root","snippet":"ForgeTrust.AppSurface.Web.Scalar This package integrates the Scalar API Reference UI into AppSurface web applications. Overview The AppSurfaceWebScalarModule provides a modern, interactive API documentation interface....","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Web.Scalar"],"sourcePath":"Web/ForgeTrust.AppSurface.Web.Scalar/README.md"},{"id":"web/forgetrust.appsurface.web.tailwind","path":"/docs/web/forgetrust.appsurface.web.tailwind","title":"ForgeTrust.AppSurface.Web.Tailwind","summary":"Tailwind CSS integration for AppSurface web applications with zero Node.js dependency.","headings":["Overview","Features","Usage","CI","Escape hatch (plugin-heavy Tailwind setups)","Notes"],"bodyText":"ForgeTrust.AppSurface.Web.Tailwind Tailwind CSS integration for AppSurface web applications with zero Node.js dependency. Overview This package wires the Tailwind standalone CLI into the AppSurface web build pipeline so your app can compile generated CSS during builds and run Tailwind in watch mode during development. Features No Node.js required : Uses the official standalone Tailwind CLI binaries. RID-aware runtime packages : Pulls in the platform-specific runtime package automatically when the package is restored. Build integration : Compiles wwwroot/css/app.css to wwwroot/css/site.gen.css by default. Development watch mode : Starts Tailwind in --watch during development when you register the service. Usage Install the package and register Tailwind in your web module: C# services . AddTailwind ( options =\u003E { options . InputPath = \u0022 wwwroot/css/app.css \u0022 ; options . OutputPath = \u0022 wwwroot/css/site.gen.css \u0022 ; } ) ; Reference the generated stylesheet from your layout: HTML \u003C link rel = \u0022 stylesheet \u0022 href = \u0022 ~/css/site.gen.css \u0022 asp-append-version = \u0022 true \u0022 /\u003E When OutputPath stays under wwwroot/ , the generated file is registered as an ASP.NET Core static web asset on clean builds and publish runs. That means Razor Class Libraries and other package-style consumers can serve the generated CSS without checking site.gen.css into source control first. That registration also stays in place for projects that disable the SDK\u0027s default content items and rely on the package to declare the generated web-root asset explicitly. Keep InputPath and OutputPath pointed at different files. The build target and the development watch service both reject configurations where the two paths resolve to the same file, even if one path uses a normalized relative form such as ./wwwroot/css/../css/app.css . During development, the watch service is non-blocking. If the Tailwind CLI is not available on the current machine, the app still starts and serves any existing CSS while logging a warning that points developers to the runtime package or TailwindCliPath override. Other startup failures still log as errors. CI ForgeTrust.AppSurface.Web.Tailwind hooks into the normal dotnet build and dotnet publish pipeline through MSBuild targets, so the default integration does not require a separate npm install or npm run build step in CI. Runtime packages download the official Tailwind checksum file and standalone binary during build or publish, then verify the binary with SHA-256 before packaging it. These downloads retry transient network failures by default, which keeps CI resilient to brief GitHub release CDN 5xx responses and timeouts without weakening checksum validation. The retry behavior is configurable with MSBuild properties: XML \u003C PropertyGroup \u003E \u003C TailwindDownloadRetries \u003E 4 \u003C/ TailwindDownloadRetries \u003E \u003C TailwindDownloadRetryDelayMilliseconds \u003E 5000 \u003C/ TailwindDownloadRetryDelayMilliseconds \u003E \u003C/ PropertyGroup \u003E Raise these values for slower CI networks. Lower them only when you prefer fail-fast behavior and have another way to provide the Tailwind CLI, such as TailwindCliPath . If you need to suppress the package-driven build temporarily, set TailwindEnabled=false in MSBuild, for example with dotnet build -p:TailwindEnabled=false or a project-level \u003CTailwindEnabled\u003Efalse\u003C/TailwindEnabled\u003E property. If you want to keep the package-driven build but point it at a different standalone Tailwind executable, set TailwindCliPath to an absolute path or a project-relative file path: XML \u003C PropertyGroup \u003E \u003C TailwindCliPath \u003E tools/tailwindcss/tailwindcss \u003C/ TailwindCliPath \u003E \u003C/ PropertyGroup \u003E On Windows, TailwindCliPath can point at the standalone binary directly or at the npm-generated .cmd or .ps1 shim. The package wraps those shims consistently in both build mode and development watch mode, so the same override works in each flow. Escape hatch (plugin-heavy Tailwind setups) If your Tailwind configuration depends on npm-only plugins or custom JavaScript tooling, keep your existing Node-based asset pipeline instead of forcing the standalone CLI path. Disable the package-driven MSBuild integration with TailwindEnabled=false , and either omit services.AddTailwind() or set options.Enabled = false so the development watch service does not start. After that, run your existing npm, pnpm, or yarn Tailwind command as part of your normal frontend build. If your custom setup still uses the standalone CLI but stores it outside the package runtime layout, prefer TailwindCliPath over editing the imported .targets file directly. Notes The generated CSS file is intended to be build output and is commonly ignored in source control. Generated CSS outside wwwroot/ still builds locally, but it is not exposed automatically through the static web asset pipeline. The platform-specific ForgeTrust.AppSurface.Web.Tailwind.Runtime.* packages are support packages consumed transitively by this package and are not usually installed directly. Tailwind CLI selection follows the current build host, not RuntimeIdentifier , because the standalone CLI runs during the build. Cross-targeted builds still execute the host-compatible binary. Windows Arm64 hosts intentionally use the win-x64 runtime under emulation. There is no ForgeTrust.AppSurface.Web.Tailwind.Runtime.win-arm64 package because Tailwind v4.1.18 does not ship a native Windows Arm64 standalone CLI.","snippet":"ForgeTrust.AppSurface.Web.Tailwind Tailwind CSS integration for AppSurface web applications with zero Node.js dependency. Overview This package wires the Tailwind standalone CLI into the AppSurface web build pipeline...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Web.Tailwind"],"sourcePath":"Web/ForgeTrust.AppSurface.Web.Tailwind/README.md"},{"id":"web/forgetrust.appsurface.web.tailwind/runtimes","path":"/docs/web/forgetrust.appsurface.web.tailwind/runtimes","title":"ForgeTrust.AppSurface.Web.Tailwind Runtime Packages","summary":"Platform-specific runtime packages that carry the official standalone Tailwind CLI binaries used by \u0060ForgeTrust.AppSurface.Web.Tailwind\u0060.","headings":["Overview","Supported Packages","Usage"],"bodyText":"ForgeTrust.AppSurface.Web.Tailwind Runtime Packages Platform-specific runtime packages that carry the official standalone Tailwind CLI binaries used by ForgeTrust.AppSurface.Web.Tailwind . Overview These packages exist so the main Tailwind package can depend on RID-specific binaries without bundling every executable into one package. Each runtime package contains the native Tailwind CLI for a single supported platform. Supported Packages ForgeTrust.AppSurface.Web.Tailwind.Runtime.win-x64 ForgeTrust.AppSurface.Web.Tailwind.Runtime.osx-x64 ForgeTrust.AppSurface.Web.Tailwind.Runtime.osx-arm64 ForgeTrust.AppSurface.Web.Tailwind.Runtime.linux-x64 ForgeTrust.AppSurface.Web.Tailwind.Runtime.linux-arm64 Note: Windows Arm64 hosts are supported via x64 emulation using ForgeTrust.AppSurface.Web.Tailwind.Runtime.win-x64 . Tailwind v4.1.18 does not publish a native Windows Arm64 standalone binary. Usage Most consumers should install only ForgeTrust.AppSurface.Web.Tailwind . These runtime packages are implementation-detail dependencies that are restored automatically through the main package. Install one directly only if you have a specialized packaging or build scenario that requires explicit control over the Tailwind CLI binary payload. During build and pack, each runtime project downloads the official Tailwind checksum file and matching standalone binary, then verifies the binary hash before adding it to the package. The download step retries transient network failures by default using TailwindDownloadRetries and TailwindDownloadRetryDelayMilliseconds . Keep those defaults for normal CI; tune them only when your build environment needs more patience for GitHub release asset downloads or intentionally wants fail-fast behavior.","snippet":"ForgeTrust.AppSurface.Web.Tailwind Runtime Packages Platform-specific runtime packages that carry the official standalone Tailwind CLI binaries used by ForgeTrust.AppSurface.Web.Tailwind . Overview These packages...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","ForgeTrust.AppSurface.Web.Tailwind Runtime Packages"],"sourcePath":"Web/ForgeTrust.AppSurface.Web.Tailwind/runtimes/README.md"},{"id":"web/forgetrust.razorwire","path":"/docs/web/forgetrust.razorwire","title":"RazorWire","summary":"RazorWire lets ASP.NET Core MVC apps update UI by returning Razor fragments from the server instead of building a separate JSON endpoint and client-state rendering loop.","headings":["60-Second Quickstart","Hero Proof","Generated UI Design Contract","Add the Module","Enable TagHelpers and Scripts","Configure Services (Optional)","Also Possible","Core Concepts","Islands","Streams and SSE","Form Enhancement","Security \u0026 Anti-Forgery","Development Experience","API Reference","RazorWireBridge","IRazorWireStreamHub","this.RazorWireStream() (controller extension)","TagHelpers","rw:island","form[rw-active]","rw:stream-source","requires-stream","\u003Ctime rw-type=\u0022local\u0022\u003E","rw:scripts"],"bodyText":"RazorWire RazorWire lets ASP.NET Core MVC apps update UI by returning Razor fragments from the server instead of building a separate JSON endpoint and client-state rendering loop. 60-Second Quickstart AppSurface has not published the public v0.1 package set yet, so the copy-paste path today is repo-local: Clone this repository and use the .NET 10 SDK. Run the MVC sample: Bash dotnet run --project examples/razorwire-mvc/RazorWireWebExample.csproj Open the URL printed in the console and navigate to /Reactivity . Wait for the Permanent Island card to load, then click the \u002B button. The Instance Score and Session Score update in place without a full-page reload. When consuming package builds from a configured feed, reference ForgeTrust.RazorWire first and then continue at Add the Module . Public NuGet install commands will replace this note when the v0.1 publishing path is live. Hero Proof examples/razorwire-mvc/Views/Shared/Components/Counter/Default.cshtml Razor \u003C div id = \u0022 counter-widget \u0022 class = \u0022 p-4 bg-white border border-slate-100 rounded-xl shadow-sm flex items-center justify-between group \u0022 \u003E \u003C div class = \u0022 flex gap-6 \u0022 \u003E \u003C div class = \u0022 space-y-0.5 \u0022 \u003E \u003C span class = \u0022 text-[10px] font-bold text-slate-400 uppercase tracking-widest \u0022 \u003E Instance Score \u003C/ span \u003E \u003C div id = \u0022 instance-score-value \u0022 class = \u0022 text-2xl font-black text-indigo-600 tabular-nums \u0022 \u003E @ Model \u003C/ div \u003E \u003C/ div \u003E \u003C div class = \u0022 space-y-0.5 \u0022 \u003E \u003C span class = \u0022 text-[10px] font-bold text-slate-400 uppercase tracking-widest \u0022 \u003E Session Score \u003C/ span \u003E \u003C div id = \u0022 session-score-value \u0022 class = \u0022 text-2xl font-black text-indigo-400 tabular-nums \u0022 \u003E 0 \u003C/ div \u003E \u003C/ div \u003E \u003C/ div \u003E \u003C form asp-controller = \u0022 Reactivity \u0022 asp-action = \u0022 IncrementCounter \u0022 method = \u0022 post \u0022 rw-active = \u0022 true \u0022 data-counter-form \u003E \u003C input type = \u0022 hidden \u0022 name = \u0022 clientCount \u0022 id = \u0022 client-count-input \u0022 value = \u0022 0 \u0022 /\u003E \u003C button type = \u0022 submit \u0022 aria-label = \u0022 Increment counter \u0022 class = \u0022 h-10 w-10 bg-indigo-600 text-white rounded-lg flex items-center justify-center hover:bg-indigo-700 active:scale-90 transition-all shadow-sm shadow-indigo-100 \u0022 \u003E \u003C svg class=\u0022w-5 h-5\u0022 fill=\u0022none\u0022 stroke=\u0022currentColor\u0022 viewBox=\u00220 0 24 24\u0022 \u003E \u003C path stroke-linecap=\u0022round\u0022 stroke-linejoin=\u0022round\u0022 stroke-width=\u00222\u0022 d=\u0022M12 4v16m8-8H4\u0022 \u003E \u003C/ path \u003E \u003C/ svg \u003E \u003C/ button \u003E \u003C/ form \u003E \u003C/ div \u003E examples/razorwire-mvc/Controllers/ReactivityController.cs C# [ HttpPost ] [ ValidateAntiForgeryToken ] public IActionResult IncrementCounter ( [ FromForm ] int clientCount ) { CounterViewComponent . Increment ( ) ; clientCount \u002B\u002B ; if ( Request . IsTurboRequest ( ) ) { return this . RazorWireStream ( ) . Update ( \u0022 instance-score-value \u0022 , CounterViewComponent . Count . ToString ( ) ) . Update ( \u0022 session-score-value \u0022 , clientCount . ToString ( ) ) . ReplacePartial ( \u0022 client-count-input \u0022 , \u0022 _CounterInput \u0022 , clientCount ) . BuildResult ( ) ; } // Safe redirect var referer = Request . Headers [ \u0022 Referer \u0022 ] . ToString ( ) ; return Url . IsLocalUrl ( referer ) ? Redirect ( referer ) : RedirectToAction ( nameof ( Index ) ) ; } examples/razorwire-mvc/Views/Reactivity/_CounterInput.cshtml Razor \u003C input type = \u0027 hidden \u0027 name = \u0027 clientCount \u0027 id = \u0027 client-count-input \u0027 value = \u0027 @ Model \u0027 /\u003E Read the focused proof path for the file-by-file walkthrough. If copying this pattern gives you a bare 400 Bad Request , anti-forgery is the first thing to check. See Security \u0026 Anti-Forgery . The source-backed snippets in this README are generated from docs:snippet markers in the sample app. After changing marked sample code, run: Bash # From the repository root: dotnet run --project tools/ForgeTrust.AppSurface.MarkdownSnippets/ForgeTrust.AppSurface.MarkdownSnippets.csproj -- generate For failed submissions, RazorWire also ships a convention-based form UX stack: default form-local fallbacks for unhandled failures, server helpers for validation errors, anti-forgery diagnostics in development, and styling/event hooks for consumers. See Failed Form UX or run the sample and visit /Reactivity/FormFailures . Generated UI Design Contract RazorWire should feel like a quiet enhancement inside the host application, not like a separate visual product placed on top of it. Package-owned generated UI follows the RazorWire generated UI design contract . Use that contract when adding or styling RazorWire-generated nodes such as form feedback, stream status affordances, or package-owned fallback UI. It defines the scope boundary, data-attribute and CSS custom-property styling surface, accessibility baseline, override model, and anti-patterns. It does not apply to app-authored forms, partials, layouts, or RazorDocs chrome. Add the Module Once you already reference the RazorWire package in your app, add RazorWireWebModule to your root module: C# public class MyRootModule : IAppSurfaceWebModule { public void RegisterDependentModules ( ModuleDependencyBuilder builder ) { builder . AddModule \u003C RazorWireWebModule \u003E ( ) ; } } Enable TagHelpers and Scripts RazorWire markup only lights up when your views import the package TagHelpers and your shared layout renders the client scripts once. Without this step, rw:island , rw:stream-source , and rw-active forms fall back to plain HTML behavior. examples/razorwire-mvc/Views/_ViewImports.cshtml Razor @ addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @ addTagHelper *, ForgeTrust.RazorWire examples/razorwire-mvc/Views/Shared/_Layout.cshtml Razor \u003C rw:scripts /\u003E Configure Services (Optional) You can customize RazorWire behavior via RazorWireOptions : C# services . AddRazorWire ( options =\u003E { options . Streams . BasePath = \u0022 /custom-stream-path \u0022 ; options . Forms . FailureMode = RazorWireFormFailureMode . Auto ; options . Forms . DefaultFailureMessage = \u0022 We could not submit this form. Check your input and try again. \u0022 ; } ) ; Also Possible Keep sidebars and other regions independent with rw:island , including lazy loading and permanent=\u0022true\u0022 persistence across page transitions. Push live updates to connected clients with IRazorWireStreamHub and rw:stream-source . Return form updates from normal MVC controllers with this.RazorWireStream() , not a separate JSON API. See the broader RazorWire MVC Example for registration, message publishing, islands, and SSE. See Failed Form UX for server failure conventions, customization, and diagnostics. See Security \u0026 Anti-Forgery for the form-update patterns that matter in production. Core Concepts Islands Islands are isolated regions of a page that can load, reload, or update independently. RazorWire renders them as Turbo Frames, so you can decompose a page into smaller Razor-backed units without introducing a separate frontend app. Streams and SSE RazorWire can push Turbo Stream updates to one or more clients over Server-Sent Events. That makes it a good fit for counters, feeds, presence lists, and other UI that should update live while staying server-rendered. Form Enhancement Standard HTML forms can return targeted stream updates instead of full reloads or redirect-first flows. The counter example above is the smallest version of that story: submit a normal MVC form, return RazorWire updates, and change only the DOM you care about. When EnableFailureUx is enabled, form[rw-active] also marks enhanced form posts with X-RazorWire-Form: true and __RazorWireForm=1 . That gives the runtime and server adapters enough context to render useful failed-submission UX without every controller hand-rolling client glue. Security \u0026 Anti-Forgery Handling anti-forgery tokens correctly is critical when updating forms via Turbo Streams. See Security \u0026 Anti-Forgery for the detailed patterns and recommendations. Development anti-forgery failures from RazorWire forms are rewritten into helpful form-local diagnostics when possible. Production responses stay safe and generic. See Failed Form UX . Development Experience RazorWire is designed for a fast feedback loop during development: Razor Runtime Compilation is automatically enabled in Development , so you can edit .cshtml files and refresh without rebuilding. Local scripts and styles automatically receive version hashes for cache busting, even without asp-append-version=\u0022true\u0022 . API Reference RazorWireBridge Frame(controller, id, viewName, model) returns a partial view wrapped in a \u003Cturbo-frame\u003E with the specified ID. FrameComponent(controller, id, componentName) renders a view component inside a \u003Cturbo-frame\u003E . IRazorWireStreamHub PublishAsync(channel, content) broadcasts a Turbo Stream fragment to every subscriber on a channel. this.RazorWireStream() (controller extension) Append(target, content) adds content to the end of the target element. Prepend(target, content) adds content to the beginning. Replace(target, content) replaces the target element entirely. Update(target, content) replaces the inner content of the target. Remove(target) removes the target element. FormError(target, title, message) updates the target with an encoded generated error block and marks the response handled. FormValidationErrors(target, ModelState, title, maxErrors, message) updates the target with a stable MVC validation summary and marks the response handled. BuildResult(statusCode) returns the stream and optionally sets the HTTP status code. TagHelpers rw:island Wraps content in a \u003Cturbo-frame\u003E . id : unique identifier for the island. src : URL to load content from. loading : load strategy such as lazy . permanent : persists the element across Turbo page transitions. swr : enables stale-while-revalidate behavior. client-module : client module path or name to mount for hybrid islands. client-strategy : mount timing such as load , visible , or idle . client-props : JSON payload passed to the client module\u0027s mount function. HTML \u003C rw:island id = \u0022 sidebar \u0022 src = \u0022 /Reactivity/Sidebar \u0022 loading = \u0022 lazy \u0022 permanent = \u0022 true \u0022 \u003E \u003C p \u003E Loading sidebar... \u003C/ p \u003E \u003C/ rw:island \u003E form[rw-active] Enhances a normal form so Turbo handles the submission and optional frame targeting. rw-active=\u0022true\u0022 enables RazorWire form handling. rw-target sets the target frame when you want to constrain the response. data-rw-form-failure-target points failed-submission UI at a local error container by simple element ID, optionally prefixed with # ; selector-like values are ignored. data-rw-form-failure=\u0022auto\u0022 uses the default fallback UI, manual only dispatches events, and off disables the failure convention for that form. Generated hidden fields __RazorWireForm and, when possible, __RazorWireFormFailureTarget help server-side adapters identify and localize form failures. HTML \u003C form asp-controller = \u0022 Reactivity \u0022 asp-action = \u0022 IncrementCounter \u0022 method = \u0022 post \u0022 rw-active = \u0022 true \u0022 \u003E \u003C input type = \u0022 hidden \u0022 name = \u0022 clientCount \u0022 value = \u0022 0 \u0022 /\u003E \u003C button type = \u0022 submit \u0022 aria-label = \u0022 Increment counter \u0022 \u003E \u002B \u003C/ button \u003E \u003C/ form \u003E rw:stream-source Subscribes the page to a RazorWire stream channel. channel : required channel name. permanent : keeps the stream source alive across Turbo visits. HTML \u003C rw:stream-source id = \u0022 rw-stream-reactivity \u0022 channel = \u0022 reactivity \u0022 permanent = \u0022 true \u0022 \u003E \u003C/ rw:stream-source \u003E requires-stream Marks an element as inactive until a named stream is connected. HTML \u003C button type = \u0022 submit \u0022 requires-stream = \u0022 reactivity \u0022 \u003E Send \u003C/ button \u003E \u003Ctime rw-type=\u0022local\u0022\u003E Localizes UTC timestamps on the client with the browser\u0027s Intl APIs. rw-display : time , date , datetime , or relative . rw-format : short , medium , long , or full . HTML \u003C time datetime = \u0022 @Model.Timestamp \u0022 rw-type = \u0022 local \u0022 rw-display = \u0022 relative \u0022 \u003E \u003C/ time \u003E rw:scripts Injects the client scripts RazorWire needs, including Turbo and the RazorWire assets. HTML \u003C rw:scripts /\u003E The script tag also carries failed-form runtime configuration derived from RazorWireOptions.Forms ; no inline configuration script is required. Utilities StringUtils ToSafeId(input, appendHash) sanitizes values for DOM IDs or anchors and can append a deterministic hash for uniqueness. Client-Side Interop RazorWire also supports hybrid islands where a server-rendered region mounts a client module: HTML \u003C rw:island id = \u0022 interactive-chart \u0022 client-module = \u0022 ChartComponent \u0022 client-strategy = \u0022 visible \u0022 client-props = \u0027 { \u0022data\u0022: [1, 2, 3] } \u0027 \u003E \u003C/ rw:island \u003E RazorWire serves /_content/ForgeTrust.RazorWire/razorwire/razorwire.js , razorwire.islands.js , and the package demo assets as normal Razor Class Library static web assets when the host has a static-web-assets manifest. The same files are also embedded into the ForgeTrust.RazorWire assembly and mapped as endpoint fallbacks by RazorWireWebModule , so packaged command-line hosts can serve the runtime even when only compiled assemblies are present. Static Export RazorWire can generate CDN-ready static output with the installable razorwire .NET tool, or with the short-lived dnx tool execution path. CDN mode is the default: extensionless internal routes such as /about are emitted as files such as about.html , and exporter-managed links, frames, scripts, stylesheets, images, \u003Cimg\u003E and \u003Csource\u003E srcset candidates, and CSS url(...) references are rewritten to the generated artifact URLs. When the conventional /_appsurface/errors/404 route is available, it emits 404.html through the same validation and rewrite path. Use --mode hybrid when the exported directory will still be served behind infrastructure that resolves application-style extensionless URLs. CDN export validates the dependencies it can discover while crawling. Missing frame routes, unsafe query-bearing frame sources, missing internal assets, and managed URLs that cannot be rewritten fail the export with RWEXPORT### diagnostics instead of producing a broken folder. The validation boundary is deliberate: app-authored JavaScript fetches, form posts, Server-Sent Events, import maps, and other runtime behavior outside markup/CSS references are not proven static by the exporter. Those package-based commands require a published package or an explicit local package source; public package publishing is still manual until the coordinated release automation tracked in #161 lands. For installation, dnx , local-package, and source-run examples, see the RazorWire CLI . Examples Focused proof path: return Razor fragments Full RazorWire MVC example Failed Form UX guide Security \u0026 Anti-Forgery","snippet":"RazorWire RazorWire lets ASP.NET Core MVC apps update UI by returning Razor fragments from the server instead of building a separate JSON endpoint and client-state rendering loop. 60-Second Quickstart AppSurface has...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":10,"sequenceKey":"razorwire-proof","canonicalSlug":null,"relatedPages":["Web/ForgeTrust.RazorWire/DESIGN.md","examples/razorwire-mvc/README.md","Web/ForgeTrust.RazorWire/Docs/form-failures.md","Web/ForgeTrust.RazorWire/Docs/antiforgery.md"],"breadcrumbs":["How-to Guides","RazorWire"],"sourcePath":"Web/ForgeTrust.RazorWire/README.md"},{"id":"web/forgetrust.razorwire.cli","path":"/docs/web/forgetrust.razorwire.cli","title":"RazorWire CLI","summary":"The **RazorWire CLI** is a command-line tool for managing RazorWire projects. Its primary feature is exporting a reactive RazorWire site into CDN-ready static files by default, with an opt-in hybrid mode for deployments that still provide server routing.","headings":["Installation","Commands","Help and validation behavior","export","RazorDocs versioned export notes"],"bodyText":"RazorWire CLI The RazorWire CLI is a command-line tool for managing RazorWire projects. Its primary feature is exporting a reactive RazorWire site into CDN-ready static files by default, with an opt-in hybrid mode for deployments that still provide server routing. The CLI uses AppSurface\u0027s command-first console mode. That means help and validation output are intentionally quiet, without Generic Host lifecycle banners, while real export runs still emit useful progress logs. Installation The RazorWire CLI is packaged as a .NET tool with the command name razorwire . Use an exact package version when running release builds so exports are reproducible. The commands in this section require ForgeTrust.RazorWire.Cli to exist on one of your configured NuGet sources, or for you to pass an explicit local package source. Public package publishing is still manual until the coordinated release automation tracked in #161 lands. Run a published package without permanently installing it: Bash dnx ForgeTrust.RazorWire.Cli@ \u003C version \u003E --yes -- export -o ./dist -p ./examples/razorwire-mvc/RazorWireWebExample.csproj The equivalent SDK spelling is: Bash dotnet tool execute ForgeTrust.RazorWire.Cli@ \u003C version \u003E --yes -- export -o ./dist -p ./examples/razorwire-mvc/RazorWireWebExample.csproj Install the tool when you want a stable razorwire command on your PATH: Bash dotnet tool install --global ForgeTrust.RazorWire.Cli --version \u003C version \u003E razorwire export -o ./dist -p ./examples/razorwire-mvc/RazorWireWebExample.csproj During repository development, run the CLI directly from source: Bash dotnet run --project Web/ForgeTrust.RazorWire.Cli -- [ command ] [ options ] When testing an unpublished package from a local folder, pack it first, pass that folder as the package source, and keep the version exact: Bash dotnet pack Web/ForgeTrust.RazorWire.Cli -c Release -o ./artifacts/packages /p:PackageVersion=0.0.0-local.1 Bash dnx ForgeTrust.RazorWire.Cli@0.0.0-local.1 --yes --source ./artifacts/packages -- --help Do not combine --version and --prerelease for exact tool installs on recent SDKs; exact prerelease versions install without the extra flag. Commands Help and validation behavior Root help ( --help ) and command help ( export --help ) are command-first by design. Validation failures, such as invalid flags or missing source options, should surface actionable CLI output without host startup and shutdown chatter. Source validation failures include a concrete recovery path. When no source or multiple sources are provided, the error points to a single-source example such as razorwire export --project ./MyApp.csproj --output ./dist and reminds developers to run razorwire export --help . Successful export runs still keep command-owned progress output so long-running work remains understandable. export Exports a RazorWire application to a static directory. Options: -o|--output \u003Cpath\u003E : Output directory where the static files will be saved (default: dist ). -r|--seeds \u003Cpath\u003E : Optional path to a file containing seed routes to crawl. -u|--url \u003Curl\u003E : Base URL of a running application used for crawling. -p|--project \u003Cpath.csproj\u003E : Path to a .NET project to run automatically and export. -d|--dll \u003Cpath.dll\u003E : Path to a .NET DLL to run automatically and export. -f|--framework \u003CTFM\u003E : Target framework for project exports. Required when --project points at a multi-targeted project. -m|--mode \u003Ccdn|hybrid\u003E : Export mode. cdn is the default and rewrites managed internal URLs to emitted static artifacts. hybrid preserves application-style internal URLs for hosts that still route extensionless paths. --app-args \u003Ctoken\u003E : Repeatable app-argument token to pass through when launching --project or --dll . --no-build : Project mode only. Skips the release publish step and reuses existing published output. Exactly one source option is required: --url , --project , or --dll . Export modes cdn mode is the default because most razorwire export runs produce folders that are uploaded to plain static hosting or a CDN. It emits extension-backed artifact URLs for exporter-managed internal references: / is emitted as index.html and may still be referenced as / . /about is emitted as about.html and internal references rewrite to /about.html . /docs/start is emitted as docs/start.html and internal references rewrite to /docs/start.html . Dotted page slugs still follow page-route rules: /docs/web/forgetrust.razorwire is emitted as docs/web/forgetrust.razorwire.html , while assets that return non-HTML content keep their real extension. RazorDocs content frames also emit .partial.html artifacts when a doc-content frame exists, so static frame navigation can fetch the content island. Assets that already have extensions, such as /css/site.css , /img/logo.png , or /_content/.../razorwire.js , keep their path. Cache-busting query strings on assets are allowed only when the query-free path maps to an exported file. The conventional /_appsurface/errors/404 page, when available, is emitted as 404.html and participates in the same CDN validation and URL rewriting. CDN validation fails the export when exporter-managed dependencies cannot be represented as static artifacts. Diagnostics use stable codes: RWEXPORT001 : a server-fetched frame route did not materialize. RWEXPORT002 : a query-bearing frame route cannot be represented as one static artifact. RWEXPORT003 : a required internal asset did not materialize. RWEXPORT004 : a managed internal URL could not be rewritten to an emitted artifact URL. hybrid mode preserves the older application-style URL behavior. Use it when the exported directory will still be served by infrastructure that resolves extensionless URLs, dynamic frame endpoints, or other live-server behavior. Hybrid mode logs missing discovered dependencies but does not enforce CDN static-safety validation. CDN mode validates the URLs the exporter owns and can see while crawling HTML and CSS: discovered page links, Turbo Frame sources, supported HTML asset references, \u003Cimg\u003E and \u003Csource\u003E srcset candidates, and CSS url(...) references. It does not prove arbitrary app-authored JavaScript fetch calls, form posts, Server-Sent Events, import maps, or other runtime behavior that is not represented as exporter-managed markup or CSS URLs. CDN export skips relative anchors that point at common source or project file extensions, such as ./Program.cs or ../Project.csproj , because those links are usually for GitHub and editor navigation rather than static-site dependencies. For other authoring-only anchors in app-rendered HTML, use data-rw-export-ignore ; the anchor remains rendered and clickable, but CDN export will not crawl, validate, or rewrite its href . When launched app processes are started by the CLI ( --project or --dll ), they run in production environment ( DOTNET_ENVIRONMENT=Production , ASPNETCORE_ENVIRONMENT=Production ). When --project is used: Project mode publishes a release build by default. The publish probe disables persistent build servers so command output capture cannot be held open by reused MSBuild nodes. Multi-targeted projects must pass -f|--framework \u003CTFM\u003E to select the target framework, for example -f net6.0 or --framework net7.0 ; omitting it causes a CLI error before publish. -f|--framework can be combined with --project and --no-build when reusing existing published output. Project mode resolves the published app DLL and launches that DLL for crawling. Add --no-build to skip publishing and reuse existing published output. When --dll is used: The CLI launches the provided DLL directly (no build or DLL resolution step). For both --project and --dll : If you do not pass --urls via --app-args , the CLI appends --urls http://127.0.0.1:0 . The launched app inherits the parent process environment, while the CLI forces ASPNETCORE_ENVIRONMENT=Production and DOTNET_ENVIRONMENT=Production for deployed-runtime semantics. The CLI waits for startup, crawls the app, then shuts the process down automatically. RazorDocs versioned export notes When the target app hosts RazorDocs: Export the live unreleased preview surface from its configured live docs root, such as /docs when versioning is off, /docs/next when versioning is on with defaults, or /foo/bar/next when the host sets RazorDocs:Routing:RouteRootPath to /foo/bar . Export exact published release trees as standalone static subtrees that already contain their own index.html , search.html , search-index.json , search.css , search-client.js , minisearch.min.js , section routes, and detail pages. Treat those exact release trees as immutable publish artifacts. The RazorDocs runtime mounts them later under {RouteRootPath}/v/{version} and may also mount the recommended one at {RouteRootPath} . The exporter recognizes custom-root RazorDocs pages by their RazorDocs client configuration or doc-content frame, not just by a /docs URL prefix. This keeps static partial generation working for mounted roots such as /foo/bar/next . Use --seeds when you want deterministic seeds for docs-specific surfaces instead of relying only on crawl discovery. For release publishing, set RazorDocs__Harvest__FailOnFailure=true in the parent environment before razorwire export --project or razorwire export --dll . The launched target app inherits that setting, fails before listening when aggregate harvest health is Failed , and the export command surfaces the target app\u0027s startup output. The strict exception summary is redacted, but ordinary target host logs may still contain operator diagnostics such as repository paths or raw exception messages. Example: Bash dotnet run --project Web/ForgeTrust.RazorWire.Cli -- export -o ./dist -u http://localhost:5233 Bash dotnet run --project Web/ForgeTrust.RazorWire.Cli -- export -o ./dist -p ./examples/razorwire-mvc/RazorWireWebExample.csproj Bash dotnet run --project Web/ForgeTrust.RazorWire.Cli -- export -o ./dist -d ./bin/Release/net10.0/MyApp.dll --app-args --urls --app-args http://127.0.0.1:5009","snippet":"RazorWire CLI The RazorWire CLI is a command-line tool for managing RazorWire projects. Its primary feature is exporting a reactive RazorWire site into CDN-ready static files by default, with an opt-in hybrid mode for...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":[],"breadcrumbs":["How-to Guides","RazorWire CLI"],"sourcePath":"Web/ForgeTrust.RazorWire.Cli/README.md"},{"id":"web/forgetrust.razorwire/design","path":"/docs/web/forgetrust.razorwire/design","title":"RazorWire Generated UI Design Contract","summary":"RazorWire helps server-rendered ASP.NET Core apps update page fragments without asking every app to invent a separate frontend runtime. That means RazorWire occasionally owns small generated UI nodes: enhancement markers, form feedback, stream connection affordances, and other package-created fragments that support RazorWire behavior.","headings":["Purpose","Scope","RazorWire Is Not RazorDocs","Visual Posture","Styling Surface","Override Model","Example Generated Component","Theming Override Example","Accessibility Baseline","Anti-Patterns","Review Questions"],"bodyText":"RazorWire Generated UI Design Contract Purpose RazorWire helps server-rendered ASP.NET Core apps update page fragments without asking every app to invent a separate frontend runtime. That means RazorWire occasionally owns small generated UI nodes: enhancement markers, form feedback, stream connection affordances, and other package-created fragments that support RazorWire behavior. This contract defines how those RazorWire-owned generated nodes should look, behave, and be overridden by host applications. It is deliberately narrower than a product design system. Scope This contract applies only to UI that the ForgeTrust.RazorWire package creates or explicitly owns. Examples in scope: package-generated form feedback package-owned stream or island status affordances package-owned fallback UI around enhanced RazorWire behavior documented attributes and custom properties on RazorWire-generated nodes Examples out of scope: arbitrary app markup inside a RazorWire form view components, partials, or layouts authored by the host app sample-app visual styling RazorDocs documentation chrome consumer-owned Tailwind, Bootstrap, or design-system classes If a node is authored by the application, RazorWire should not impose a visual opinion on it. RazorWire may add behavior attributes or script hooks where the feature requires them, but the host application owns the element\u0027s design. RazorWire Is Not RazorDocs RazorDocs owns a full documentation workspace with its own editorial chrome, navigation, search, and package-specific design language. RazorWire does not. RazorWire-generated UI should inherit from the application around it. It should feel like a quiet enhancement inside the host app, not like a branded AppSurface component transplanted onto the page. Use the RazorDocs design language only when working on RazorDocs. For RazorWire, this file is the package-level source of truth. Visual Posture RazorWire-owned UI should be: calm: use restrained color and no dramatic motion compact: fit naturally near the element or form that needs feedback app-inheriting: rely on font , color , and inherited spacing where practical accessible: visible focus, readable contrast, predictable keyboard flow low chrome: no heavy cards, promotional styling, or ornamental decoration resilient: wrap cleanly on narrow screens and inside constrained forms Generated UI should explain state, not compete with the app\u0027s primary interface. Styling Surface RazorWire-generated UI should expose two styling layers: Stable data-rw-* attributes for selectors and behavior. CSS custom properties for host-controlled visual defaults. Prefer data attributes over package-specific class names for generated nodes. Data attributes make ownership explicit, avoid collisions with host CSS naming, and give consumers predictable selectors without implying that RazorWire is shipping a general-purpose component library. Generated UI should use a small custom-property set with package defaults. A feature may define additional properties when it needs them, but it should document the full surface next to the feature. Recommended shared properties: CSS : root { --rw-ui-font : inherit ; --rw-ui-surface : transparent ; --rw-ui-text : currentColor ; --rw-ui-muted-text : color-mix(in srgb , currentColor 72 % , transparent) ; --rw-ui-border : color-mix(in srgb , currentColor 24 % , transparent) ; --rw-ui-accent : # 2563eb ; --rw-ui-danger : # b42318 ; --rw-ui-radius : 0.375 rem ; --rw-ui-gap : 0.5 rem ; } Package CSS should keep defaults modest and overrideable. Do not require a build step, sample-app Tailwind setup, or package-wide visual theme for RazorWire-generated UI to work. Override Model Consumers should be able to override generated UI at three levels: Global: set --rw-ui-* properties on :root , body , or an application shell. Form-level: set custom properties or supported data-rw-* attributes on the form or nearest generated RazorWire container. Target-level: override a specific generated node by selecting its documented data-rw-ui and target metadata. Use the narrowest override that matches the decision. Global overrides are good for product-wide color and radius alignment. Form-level overrides are better when one workflow needs a different density or state color. Target-level overrides are for one-off corrections around a specific generated node. Feature docs must name the supported attributes and custom properties before consumers are expected to depend on them. Example Generated Component A future generated form-failure summary should follow this shape: scoped data attributes, semantic roles, readable text, and no dependence on host CSS classes. HTML \u003C div data-rw-ui = \u0022 form-failure \u0022 data-rw-severity = \u0022 error \u0022 data-rw-target = \u0022 payment-step \u0022 role = \u0022 status \u0022 aria-live = \u0022 polite \u0022 \u003E \u003C p data-rw-ui = \u0022 form-failure-title \u0022 \u003E We could not submit this form. \u003C/ p \u003E \u003C ul data-rw-ui = \u0022 form-failure-list \u0022 \u003E \u003C li data-rw-ui = \u0022 form-failure-item \u0022 \u003E Refresh the page and try again. \u003C/ li \u003E \u003C/ ul \u003E \u003C/ div \u003E The package-owned default CSS should stay close to this level of opinion: CSS [ data-rw-ui = \u0022 form-failure \u0022 ] { display : grid ; gap : var ( --rw-ui-gap , 0.5 rem ) ; color : var ( --rw-ui-danger , # b42318 ) ; font : var ( --rw-ui-font , inherit ) ; } Theming Override Example The host app can align generated feedback with its own design system without replacing the RazorWire behavior. CSS : root { --rw-ui-danger : # 9f1239 ; --rw-ui-radius : 0.25 rem ; } . checkout-form { --rw-ui-gap : 0.375 rem ; } . checkout-form [ data-rw-ui = \u0022 form-failure \u0022 ] [ data-rw-target = \u0022 payment-step \u0022 ] { padding-block : 0.5 rem ; border-block-start : 1 px solid var ( --rw-ui-danger ) ; } In this example, .checkout-form is a host-owned selector on the form or nearest generated RazorWire container. It could be a class, ID, or app-specific data attribute. The override changes the presentation of a generated node. It does not require replacing RazorWire scripts, copying sample-app classes, or changing unrelated app markup. Accessibility Baseline Every RazorWire-generated UI feature should document and verify: semantic role and accessible name when the node communicates state aria-live behavior for asynchronous feedback keyboard reachability for interactive generated controls visible focus treatment for generated focusable elements contrast against inherited and default surfaces mobile wrapping without clipped text or horizontal scrolling behavior when JavaScript enhancement fails or is unavailable Generated feedback should stay close to the interaction that caused it. When focus should move, the feature must document the focus rule and provide tests for it. Anti-Patterns Avoid these by default: global toast systems for local form failures modal takeovers for recoverable inline feedback sample-app Tailwind dependencies in package-generated UI a package-wide RazorWire visual theme hard-coded colors that cannot be overridden with custom properties generated UI that restyles consumer-authored form fields or layout hidden state changes that screen readers cannot observe animation that is required to understand the UI state If a feature seems to need one of these, write down the product reason before adding it. Most RazorWire-generated UI should be smaller and quieter than the host page around it. Review Questions Before adding or changing generated UI, ask: Does RazorWire own this node, or is the app the real owner? Which data-rw-* attributes and custom properties are part of the supported contract? Can a host app make this match its own design system without replacing package code? Does the UI remain understandable with JavaScript disabled, slow streams, or failed form submissions? Are accessibility behavior, defaults, and pitfalls documented next to the feature?","snippet":"RazorWire Generated UI Design Contract Purpose RazorWire helps server-rendered ASP.NET Core apps update page fragments without asking every app to invent a separate frontend runtime. That means RazorWire occasionally...","pageType":"reference","pageTypeLabel":"Reference","pageTypeVariant":"neutral","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":null,"sequenceKey":null,"canonicalSlug":null,"relatedPages":["Web/ForgeTrust.RazorWire/README.md","Web/ForgeTrust.RazorWire/Docs/antiforgery.md"],"breadcrumbs":["How-to Guides","RazorWire Generated UI Design Contract"],"sourcePath":"Web/ForgeTrust.RazorWire/DESIGN.md"},{"id":"web/forgetrust.razorwire/docs/antiforgery","path":"/docs/web/forgetrust.razorwire/docs/antiforgery","title":"Security \u0026 Anti-Forgery","summary":"When using RazorWire Turbo Streams to replace or update parts of a page that contain forms, the original Anti-Forgery token hidden input may be lost. To prevent \u0060400 Bad Request\u0060 errors on subsequent form submissions, ensure the token is included in your updated HTML.","headings":["Recommended: Use the \u003Cform\u003E TagHelper with replace","Fallback: Explicit Token for update Actions","Avoiding Duplicate Tokens","Summary","Symptom: The First Submit Works, The Second Submit Returns 400","Symptom: The Anti-Forgery Error Is Helpful In Development But Generic In Production"],"bodyText":"Security \u0026 Anti-Forgery When using RazorWire Turbo Streams to replace or update parts of a page that contain forms, the original Anti-Forgery token hidden input may be lost. To prevent 400 Bad Request errors on subsequent form submissions, ensure the token is included in your updated HTML. RazorWire\u0027s failed-form convention improves the development experience around this failure. Enhanced forms are marked with X-RazorWire-Form: true and __RazorWireForm=1 ; when anti-forgery validation fails for one of those requests, RazorWire can rewrite the failure into a helpful 400 response with safe production text or detailed development diagnostics. See Failed Form UX . Recommended: Use the \u003Cform\u003E TagHelper with replace If your partial view contains the entire \u003Cform\u003E element, the ASP.NET Core TagHelper automatically injects the hidden anti-forgery token: Razor \u003C!-- _MyForm.cshtml --\u003E \u003C form asp-action = \u0022 Submit \u0022 method = \u0022 post \u0022 id = \u0022 my-form \u0022 \u003E \u003C input type = \u0022 text \u0022 name = \u0022 data \u0022 /\u003E \u003C button type = \u0022 submit \u0022 \u003E Submit \u003C/ button \u003E \u003C/ form \u003E Important: This approach requires using the replace Turbo Stream action (or ReplacePartial server-side helper). The replace action replaces the entire element, so when the partial is rendered, the TagHelper runs and emits a fresh token. C# // Controller return this . RazorWireStream ( ) . ReplacePartial ( \u0022 my-form \u0022 , \u0022 _MyForm \u0022 , model ) . BuildResult ( ) ; Fallback: Explicit Token for update Actions The update Turbo Stream action replaces only the inner HTML of the target element\u2014it does not replace the element itself. If your outer \u003Cform\u003E tag remains in the DOM and only its contents are swapped, the TagHelper won\u0027t run again, and the hidden token will be stripped. In this scenario, your partial should explicitly include the token: Razor \u003C!-- _FormFields.cshtml --\u003E @ Html. AntiForgeryToken ( ) \u003C input type = \u0022 text \u0022 name = \u0022 data \u0022 /\u003E \u003C button type = \u0022 submit \u0022 \u003E Submit \u003C/ button \u003E C# // Controller return this . RazorWireStream ( ) . UpdatePartial ( \u0022 my-form \u0022 , \u0022 _FormFields \u0022 , model ) . BuildResult ( ) ; Avoiding Duplicate Tokens If _FormFields.cshtml is rendered inside an outer \u003Cform asp-action=\u0022...\u0022 method=\u0022post\u0022\u003E on initial page load, the TagHelper will also inject a token. To avoid duplicate tokens or mixed patterns: Option A (Recommended): Set asp-antiforgery=\u0022false\u0022 on the outer \u003Cform\u003E and rely solely on @Html.AntiForgeryToken() in your fragment: Razor \u003C form asp-action = \u0022 Submit \u0022 method = \u0022 post \u0022 asp-antiforgery = \u0022 false \u0022 id = \u0022 my-form \u0022 \u003E @ await Html. PartialAsync ( \u0022 _FormFields \u0022 ) \u003C/ form \u003E Option B: Use replace instead of update so the entire \u003Cform\u003E (with TagHelper) is replaced consistently. Summary Stream Action What It Does Token Strategy replace / ReplacePartial Replaces entire element Use \u003Cform\u003E TagHelper (automatic) update / UpdatePartial Replaces inner HTML only Use @Html.AntiForgeryToken() explicitly Both methods provide the same security protection when used correctly. Symptom: The First Submit Works, The Second Submit Returns 400 The most common cause is a stale or missing anti-forgery token after a stream update. Replace the whole form, or render @Html.AntiForgeryToken() inside the updated fragment. Symptom: The Anti-Forgery Error Is Helpful In Development But Generic In Production That is intentional. Development diagnostics are controlled by RazorWireOptions.Forms.EnableDevelopmentDiagnostics and IWebHostEnvironment.IsDevelopment() . Production responses avoid exposing token details to end users.","snippet":"Security \u0026 Anti-Forgery When using RazorWire Turbo Streams to replace or update parts of a page that contain forms, the original Anti-Forgery token hidden input may be lost. To prevent 400 Bad Request errors on...","pageType":"troubleshooting","pageTypeLabel":"Troubleshooting","pageTypeVariant":"troubleshooting","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"How-to Guides","publicSection":"how-to-guides","publicSectionLabel":"How-to Guides","isSectionLanding":false,"order":30,"sequenceKey":"razorwire-proof","canonicalSlug":null,"relatedPages":["Web/ForgeTrust.RazorWire/README.md","Web/ForgeTrust.RazorWire/Docs/form-failures.md","Web/ForgeTrust.RazorWire/DESIGN.md"],"breadcrumbs":["How-to Guides","Security \u0026 Anti-Forgery"],"sourcePath":"Web/ForgeTrust.RazorWire/Docs/antiforgery.md"},{"id":"web/forgetrust.razorwire/docs/form-failures","path":"/docs/web/forgetrust.razorwire/docs/form-failures","title":"Failed Form UX","summary":"RazorWire-enhanced forms now have a convention for server failures. A form with \u0060rw-active=\u0022true\u0022\u0060 gets request markers, a default form-local fallback UI for unhandled failures, server-side helpers for high-quality validation errors, and development diagnostics for anti-forgery failures.","headings":["Quickstart","Customize The Default Styling","Development Diagnostics","Options","Server API","Runtime Events","Test Workflow","Symptom: A Failed Form Shows A Full Error Page","Symptom: The Error Appears In The Wrong Place","Symptom: A Validation Error Appears Twice","Symptom: Anti-Forgery Fails After A Partial Update","Safe Reporting"],"bodyText":"Failed Form UX RazorWire-enhanced forms now have a convention for server failures. A form with rw-active=\u0022true\u0022 gets request markers, a default form-local fallback UI for unhandled failures, server-side helpers for high-quality validation errors, and development diagnostics for anti-forgery failures. AppSurface has not published the public v0.1 package set yet, so the one-copy path today is the in-repo MVC sample: Bash dotnet run --project examples/razorwire-mvc/RazorWireWebExample.csproj Open the printed URL and visit /Reactivity/FormFailures . When consuming package builds from a configured feed, reference ForgeTrust.RazorWire first and then continue with the form markup below. Public NuGet install commands will replace this repo-local note when publishing is live. Quickstart Add a local error target to any enhanced form: Razor \u003C form asp-action = \u0022 Save \u0022 method = \u0022 post \u0022 rw-active = \u0022 true \u0022 data-rw-form-failure-target = \u0022 profile-errors \u0022 \u003E \u003C div id = \u0022 profile-errors \u0022 data-rw-form-errors \u003E \u003C/ div \u003E \u003C input name = \u0022 displayName \u0022 /\u003E \u003C button type = \u0022 submit \u0022 \u003E Save \u003C/ button \u003E \u003C/ form \u003E When the server returns an unhandled 400 , 401 , 403 , 422 , or 500 response, the runtime renders a scoped fallback block inside #profile-errors . The block is tagged with data-rw-form-error-generated=\u0022true\u0022 , gets an accessible live-region role, and is removed on the next submit or successful submit. For validation failures, prefer a server-handled stream: C# [ HttpPost ] [ ValidateAntiForgeryToken ] public IActionResult Save ( [ FromForm ] string ? displayName ) { if ( string . IsNullOrWhiteSpace ( displayName ) ) { ModelState . AddModelError ( nameof ( displayName ) , \u0022 Display name is required. \u0022 ) ; } if ( ! ModelState . IsValid ) { return this . RazorWireStream ( ) . FormValidationErrors ( \u0022 profile-errors \u0022 , ModelState ) . BuildResult ( StatusCodes . Status422UnprocessableEntity ) ; } return this . RazorWireStream ( ) . Update ( \u0022 profile-errors \u0022 , string . Empty ) . BuildResult ( ) ; } FormValidationErrors marks the response as handled by setting X-RazorWire-Form-Handled: true , so the runtime will not duplicate the server-rendered error UI. Customize The Default Styling The default fallback CSS is injected once by the runtime and only targets generated RazorWire form errors. Consumers can tune it with CSS variables on a form, a containing section, or global stylesheet: CSS . account-form { --rw-form-error-border : # 0f766e ; --rw-form-error-bg : # f0fdfa ; --rw-form-error-title : # 115e59 ; --rw-form-error-text : # 134e4a ; --rw-form-error-radius : 4 px ; --rw-form-error-spacing : 1 rem ; } Use data-rw-form-failure=\u0022manual\u0022 when the app wants to render everything itself: Razor \u003C form asp-action = \u0022 Save \u0022 method = \u0022 post \u0022 rw-active = \u0022 true \u0022 data-rw-form-failure = \u0022 manual \u0022 data-account-errors = \u0022 #account-errors \u0022 \u003E \u003C div id = \u0022 account-errors \u0022 \u003E \u003C/ div \u003E \u003C button type = \u0022 submit \u0022 \u003E Save \u003C/ button \u003E \u003C/ form \u003E JavaScript document . addEventListener ( \u0027 razorwire:form:failure \u0027 , event =\u003E { const form = event . target ; const target = document . querySelector (form . getAttribute ( \u0027 data-account-errors \u0027 )) ; if ( ! target) return ; event . preventDefault () ; target . textContent = event . detail . message ; } ) ; Development Diagnostics In Development , RazorWire rewrites anti-forgery validation failures for RazorWire form requests into a helpful 400 response. The diagnostic explains that the token is missing or stale, gives fixes, and links back to Security \u0026 Anti-Forgery . In production, the response remains safe for users and does not expose implementation details. The adapter recognizes RazorWire form requests by: X-RazorWire-Form: true , which the runtime adds to enhanced form submissions. __RazorWireForm=1 , which the form[rw-active] TagHelper emits as a hidden marker for fallback server detection. If the form declares data-rw-form-failure-target=\u0022profile-errors\u0022 , the TagHelper also emits __RazorWireFormFailureTarget=profile-errors . The anti-forgery adapter uses that value to stream diagnostics into the form-local target when the request can be read safely. It does not parse multipart bodies for classification or target discovery. Options Configure failed-form behavior through RazorWireOptions.Forms : C# services . AddRazorWire ( options =\u003E { options . Forms . EnableFailureUx = true ; options . Forms . FailureMode = RazorWireFormFailureMode . Auto ; options . Forms . EnableDevelopmentDiagnostics = true ; options . Forms . DefaultFailureMessage = \u0022 We could not submit this form. Check your input and try again. \u0022 ; } ) ; EnableFailureUx disables all failed-form request markers, events, fallback rendering, runtime handling, and anti-forgery rewriting when set to false . FailureMode.Auto renders the default fallback UI for unhandled failures. FailureMode.Manual dispatches failure events but does not render fallback UI. FailureMode.Off disables the failure convention by default. EnableDevelopmentDiagnostics controls detailed diagnostics in development only. DefaultFailureMessage is the generic fallback message for unhandled client-rendered failures. Null, empty, or whitespace-only values fall back to RazorWire\u0027s safe default. When EnableFailureUx is true , per-form data-rw-form-failure=\u0022auto\u0022 , manual , or off overrides the global failure mode. Server API this.RazorWireStream() includes two form-focused helpers: FormError(target, title, message) renders a form-local error block and marks the response handled. FormValidationErrors(target, ModelState, title, maxErrors, message) renders a stable ModelState summary, caps long lists, and marks the response handled. BuildResult(statusCode) can set the HTTP status while returning a Turbo Stream. Use 422 for validation responses, 400 for malformed requests, and keep unexpected 500 failures unhandled unless the app has a specific recovery UI. Runtime Events The runtime dispatches: razorwire:form:submit-start razorwire:form:failure razorwire:form:diagnostic razorwire:form:submit-end razorwire:form:failure is cancelable. Call event.preventDefault() to suppress the default fallback while still using FailureMode.Auto . The event detail includes form , target , message , and optional developmentDiagnostic . Test Workflow Runtime tests live beside the RazorWire static asset: Bash node --test Web/ForgeTrust.RazorWire/test/ * .test.mjs CI runs the same tests with npm ci --prefix Web/ForgeTrust.RazorWire followed by npm test --prefix Web/ForgeTrust.RazorWire . Server behavior is covered by the RazorWire unit tests: Bash dotnet test Web/ForgeTrust.RazorWire.Tests/ForgeTrust.RazorWire.Tests.csproj Browser-level sample behavior is covered by the RazorWire integration tests: Bash dotnet test Web/ForgeTrust.RazorWire.IntegrationTests/ForgeTrust.RazorWire.IntegrationTests.csproj Symptom: A Failed Form Shows A Full Error Page Confirm the form has rw-active=\u0022true\u0022 and that \u003Crw:scripts /\u003E is rendered once in the page layout. Without the runtime, the browser falls back to normal form navigation. Symptom: The Error Appears In The Wrong Place Add data-rw-form-failure-target=\u0022your-errors-id\u0022 and make sure the target exists before submit. Use a simple id for server-handled anti-forgery diagnostics. The client can resolve ids or CSS selectors, but server-generated Turbo Streams target ids. Symptom: A Validation Error Appears Twice Use FormError or FormValidationErrors for server-rendered failure UI. Those helpers set X-RazorWire-Form-Handled: true , which tells the runtime not to render the default fallback. Symptom: Anti-Forgery Fails After A Partial Update Refresh the token whenever a stream replaces form contents. Prefer ReplacePartial for the whole \u003Cform\u003E so the MVC Form TagHelper emits a fresh token, or include @Html.AntiForgeryToken() inside updated form fields. See Security \u0026 Anti-Forgery . Safe Reporting Production users should see short recovery messages. Detailed diagnostics should stay in development or server logs. When reporting failed-form bugs, include the action route, HTTP status, response content type, whether X-RazorWire-Form-Handled was present, and whether the form had data-rw-form-failure-target .","snippet":"Failed Form UX RazorWire-enhanced forms now have a convention for server failures. A form with rw-active=\u0022true\u0022 gets request markers, a default form-local fallback UI for unhandled failures, server-side helpers for...","pageType":"guide","pageTypeLabel":"Guide","pageTypeVariant":"guide","audience":null,"component":null,"aliases":[],"keywords":[],"status":null,"navGroup":"Troubleshooting","publicSection":"troubleshooting","publicSectionLabel":"Troubleshooting","isSectionLanding":false,"order":25,"sequenceKey":"razorwire-proof","canonicalSlug":null,"relatedPages":["Web/ForgeTrust.RazorWire/README.md","Web/ForgeTrust.RazorWire/Docs/antiforgery.md","examples/razorwire-mvc/README.md"],"breadcrumbs":["Troubleshooting","Failed Form UX"],"sourcePath":"Web/ForgeTrust.RazorWire/Docs/form-failures.md"}]}