Skip to content

Migrating from the built-in Router

Drop-in by design: @page pages keep working, authorization stays Microsoft's code, and the built-in <Found> template ports over verbatim. Migrate first, adopt features incrementally.

The parameter mapping

The built-in Router's companion components - RouteView, AuthorizeRouteView, FocusOnNavigate - consume a RouteData, not the Router itself. Brouter builds that RouteData for every matched page and hands it to those framework components for you.

Built-in Router stackBrouter
<Found> + AuthorizeRouteView + fragmentsFlat Authorizing/NotAuthorized fragments on <Brouter>, or an unchanged <Found Context="routeData"> for full control
RouteView / AuthorizeRouteView DefaultLayoutDefaultLayout on <Brouter>
AuthorizeRouteView ResourceResource on <Brouter>
<NotFound><NotFound> unchanged, or a NotFoundUrl redirect
<Navigating><Navigating> unchanged
AppAssembly / AdditionalAssemblies / OnNavigateAsyncSame-named parameters

Zero-template authorization

For the common case - [Authorize] on pages, a layout, fallback UI - no routing template is needed at all. Setting any of NotAuthorized / Authorizing / Resource routes every component-rendering route through the framework's own AuthorizeRouteView: policy evaluation, per-page @layout resolution and live authentication-state changes are all Microsoft's implementation. With nothing configured, Brouter's native rendering fails closed - instantiating an [Authorize] component throws with guidance rather than silently skipping the check.

<Brouter AppAssembly="@typeof(App).Assembly" DefaultLayout="@typeof(MainLayout)">
    <Authorizing>Checking credentials…</Authorizing>
    <NotAuthorized><RedirectToLogin /></NotAuthorized>
    <NotFound>Sorry, there's nothing here.</NotFound>
    <Navigating>Loading…</Navigating>
</Brouter>

As with the built-in stack, the app still provides AddCascadingAuthenticationState() and AddAuthorizationCore().

Full control: the Found template

Need arbitrary per-navigation markup around the page - telemetry publishers, a custom AuthorizeRouteView subclass, FocusOnNavigate? The built-in Router's <Found Context="routeData"> block ports over verbatim. Found applies to every route that renders a Component; routes rendering a Content fragment and outlet-hosted children deliberately ignore it (nested outlets are Brouter's own layout model).

<Brouter AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized><RedirectToLogin /></NotAuthorized>
        </AuthorizeRouteView>
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
</Brouter>

Observing RouteData from anywhere

The committed navigation's framework RouteData (or null on not-found) is cascaded unnamed-by-type to every descendant - breadcrumbs, telemetry and route-data publishers can observe it with a plain [CascadingParameter], no template plumbing.

@code {
    [CascadingParameter] public RouteData? RouteData { get; set; }

    protected override void OnParametersSet()
    {
        // fires on every committed navigation
    }
}

A practical migration path

  • Swap <Router> for <Brouter>, keeping AppAssembly, <Found>, <NotFound> and <Navigating> as they are - or drop <Found> for the flat authorization parameters.
  • Register AddBitBrouterServices() and verify the app behaves identically - templates, layouts and authorization should be unchanged.
  • Adopt features where they earn their keep: a guard on an admin area, a loader on a data-heavy page, view transitions app-wide.
  • Hand-declare a <Broute> shadow over a discovered @page when a page needs route-level behavior without being rewritten (see @page discovery).