Route parameters
How URL segments become strongly-typed values in your components - by-name
[Parameter] binding, the cascaded parameter bag, wildcards, and fallbacks.
<Content> - visit a counter link below, change it, and
come back: route content can share state with its host like any other component tree.
Typed binding via constraints
A parameter with a type constraint doesn't just restrict what matches - it
converts the value before your component sees it: {init:int}
arrives as an int, {day:datetime} as a DateTime
(invariant culture). When constraints chain, the last type constraint decides the
CLR type; validation constraints (min, regex, ...) only gate the
match. Route values bind automatically to same-named [Parameter] properties on
a Component-rendered page - and [BrouterParameter(Name = "...")]
overrides the name when the property can't (or shouldn't) match the template's.
@* {init:int} binds the segment as an int. *@ <Broute Path="/counter/{init:int}" Component="@typeof(CounterPage)" /> // CounterPage.razor - bound by name, already converted: [Parameter] public int Init { get; set; } // or bind a differently-named property explicitly: [Parameter, BrouterParameter(Name = "init")] public int StartValue { get; set; }
The cascaded parameter bag
Every matched route also cascades a BrouterRouteParameters value (cascading
parameter name "RouteParameters"; it's also the argument of a
<Content Context="p"> fragment). It's the escape hatch when you don't
want one property per parameter - keys are case-insensitive, and the typed getters convert
strings to enums, Guids, and any scalar on demand.
| Member | Behavior |
|---|---|
| this[key] | Raw bound value (object) or null when absent. |
| Contains(key) | Whether the template bound this parameter. |
| Get<T>(key) | Convert or throw - distinguishes missing from unconvertible. |
| TryGet<T>(key, out v) | Convert without throwing. |
| GetOrDefault<T>(key, fallback) | Convert or return the fallback. |
[CascadingParameter(Name = "RouteParameters")] public BrouterRouteParameters Parameters { get; set; } = BrouterRouteParameters.Empty; // Parameters.GetOrDefault<int>("init", 0), Parameters.TryGet<Guid>("id", out var id), ...
Optionals, defaults & catch-alls
A trailing {username?} binds null when the URL omits it - so bind
it to a nullable property. {action=Index} supplies its default instead of
null. A catch-all ({**slug}) binds the entire remaining path, slashes
included, always as a string (constraints on a catch-all validate but never
convert). See the template reference for every
shape and its matching rules.
Query-string binding
Query values bind through the framework's [SupplyParameterFromQuery] as usual.
For types the framework can't parse - enums, Guid, nullables of any scalar,
or string[] for repeated pairs (?tag=a&tag=b) - annotate the
property with [BrouterQuery] and Brouter converts it for you. Reading without
binding also works: Brouter.Location.GetQuery("page") /
GetQueryAll("tag").
[Parameter, SupplyParameterFromQuery] public string? Q { get; set; } // Types the framework can't supply - Brouter converts them: [Parameter, BrouterQuery] public SortOrder? Sort { get; set; } [Parameter, BrouterQuery(Name = "tag")] public string[]? Tags { get; set; }
Wildcards & the 404 fallback
A bare * matches any single segment without binding a value - useful for
patterns where the segment's content doesn't matter. Wildcards rank below every named
parameter in specificity, so they only win when nothing more specific matches. When
no route matches at all, the router follows NotFoundUrl (this demo
redirects to its /404 page); alternatively an inline
<NotFound> fragment can render in place without changing the URL.
@* Any first segment, literal "test" second. *@ <Broute Path="/*/test" ... /> @* Router-level fallback wiring: *@ <Brouter NotFoundUrl="404"> ... </Brouter>