class

Analyzer::CSharp::Razor

Inherits Analyzer < FileHelper < Reference < Object

Razor Pages (.cshtml) and Blazor components (.razor) declare their routes with an @page directive in the markup, not in C# routing code.

A Razor page's URL defaults to its path under Pages/ (Areas/{area}/Pages/ adds the area), a relative template is appended to that and a / or ~/ template replaces it. Verbs come from its On{Verb}{Handler}[Async] handlers, in the .cshtml.cs page model or an inline @functions block. A Blazor component lists absolute templates, one per @page or @attribute [Route]; it is navigated to with GET and, when it takes [SupplyParameterFromForm] values, posted to as a static-SSR form.

Constants

BIND_PROPERTIES = /\[BindProperties\b/
BIND_PROPERTY = /\[BindProperty\b([^\]]*)#{PROPERTY}/
COMMENT = /@\*.*?\*@|\/\*.*?\*\/|\/\/[^\n]*/m

Razor @* *@, C# block and line comments. Removed before matching so a commented-out route or handler does not count; newlines are kept so line numbers still line up.

HANDLER = /\bpublic\s+(?:(?:async|virtual|override|new)\s+)*#{TYPE}\s+On(Get|Post|Put|Delete|Patch)(\w*)\s*\(((?:[^()]|\([^()]*\))*)\)/

Handlers must be public; the access modifier keeps calls such as await OnPostAsync() from reading as declarations.

LIFECYCLE = /\b(?:protected|public)\s+override\s+(?:async\s+)?#{TYPE}\s+(OnInitialized(?:Async)?)\s*\(\s*\)/

The lifecycle method a component's request runs first: static SSR renders it on the server for every GET.

NAME_ARGUMENT = /\bName\s*=\s*"([^"]+)"/
PAGE_DIRECTIVE = /^[ \t]*@page\b(?:[ \t]+"([^"\n]*)")?/m

Line-anchored so a @@page CSS rule (Razor's escaped @) and prose mentioning @page do not count.

PLACEHOLDER = /\{([^{}]+)\}/
PROPERTY = ("\\]\\s*(?:\\[[^\\]]*\\]\\s*)*public\\s+(?:(?:required|virtual|override|new)\\s+)*" + TYPE) + "\\s+(\\w+)"

The rest of the attribute list, then public [required ...] Type Name.

ROUTE_ATTRIBUTE = /^[ \t]*@attribute\s+\[Route\(\s*"([^"\n]*)"/m
SETTABLE = /\bpublic\s+(?:(?:required|virtual|override|new)\s+)*#{TYPE}\s+(\w+)\s*\{\s*get;\s*set;/

Under a class-level [BindProperties], every public settable property.

SUPPLIED = /\bSupplyParameterFrom(Query|Form)\b(?:\s*\(([^)]*)\))?[^\]]*#{PROPERTY}/
TYPE = "(?:\\([^()]*\\)|[\\w.]+(?:<[^;{}()=]*>)?)[?\\[\\]]*"

Task<ActionResult<Dictionary<string, int>>>, int[], string?, (int, string).

USE_MAUI = /<UseMaui>\s*true\s*<\/UseMaui>/i

A .NET MAUI Blazor Hybrid app renders its components in a native WebView: there is no HTTP server, so its @page routes are not endpoints.

Class methods

tech_name
Source

Instance methods

analyze
Source
tech

Instance-side view of the same declaration. The per-file rescues live on this base class, which has no way to name the analyzer that is running inside them, so a skipped file could not be attributed to a tech. Deriving it from analyzer_for keeps the name written exactly once.

Source