# Blazor Routing & Navigation ## Route Definition Routes map URL paths to Blazor components. ### Basic Route Definition ```csharp @page "/product" @page "/product/{id}"

Product: @Id

@code { [Parameter] public string? Id { get; set; } } ``` **How it works:** - `@page` directive makes component routable - Parameter name in URL (`{id}`) must match parameter name in `@code` block - Multiple `@page` directives supported (same component, multiple routes) ### Route Parameters ```csharp @page "/product/{id}"

Product: @id

@page "/category/{categoryId}/product/{productId}"

Category: @categoryId, Product: @productId

@code { [Parameter] public string? id { get; set; } [Parameter] public string? categoryId { get; set; } [Parameter] public string? productId { get; set; } } ``` **Parameter Matching:** - Blazor matches route segments to parameter names (case-insensitive) - `{id}` in route matches `Id` parameter - Extra parameters in URL are ignored ### Route Constraints Route constraints enforce parameter type and format: ```csharp @page "/product/{id:int}" @page "/order/{orderId:long}" @page "/user/{id:guid}" @page "/article/{slug:string}" @page "/event/{date:datetime}" @page "/price/{amount:decimal}" @page "/flag/{active:bool}" @page "/value/{num:double}" @code { [Parameter] public int id { get; set; } [Parameter] public Guid id { get; set; } [Parameter] public bool active { get; set; } } ``` **Built-in Constraints:** - `:int` - Integer values - `:long` - Long integers - `:guid` - GUID format - `:bool` - Boolean - `:datetime` - DateTime format - `:decimal` - Decimal numbers - `:double` / `:float` - Floating point - `:string` - Any string (default) ### Optional Route Parameters ```csharp @page "/search" @page "/search/{searchTerm}"

Search term: @(searchTerm ?? "All results")

@code { [Parameter] public string? searchTerm { get; set; } } ``` ### Catch-All Routes ```csharp @page "/{*pageRoute}"

Page not found: @pageRoute

@code { [Parameter] public string? pageRoute { get; set; } } ``` ## Navigation ### Programmatic Navigation ```csharp @inject NavigationManager Navigation @code { private void GoHome() { Navigation.NavigateTo("/"); } private void GoToUser() { Navigation.NavigateTo("/user/123"); } } ``` ### Navigation with Options ```csharp // Replace browser history entry instead of adding new one Navigation.NavigateTo("/home", replace: true); // Force full page reload from server Navigation.NavigateTo("/refresh", forceLoad: true); // Combine options Navigation.NavigateTo("/new-page", replace: true, forceLoad: true); ``` **When to use `forceLoad: true`:** - After logout to clear client-side state - Accessing completely different app - Clearing service worker cache - Full server-side initialization needed ### NavLink Component NavLink automatically highlights active route: ```csharp 🏠 Home 📦 Products About @code { // CSS class applied to active NavLink: active } ``` **Match options:** - `NavLinkMatch.All` - Exact URL match required - `NavLinkMatch.Prefix` - URL starts with href (default) - `NavLinkMatch.None` - Never highlights **CSS:** ```css a.active { color: white; background-color: blue; } ``` ### Listen to Location Changes ```csharp @implements IDisposable @inject NavigationManager Navigation

Current location: @Navigation.Uri

@code { protected override void OnInitialized() { Navigation.LocationChanged += LocationChanged; } private void LocationChanged(object? sender, LocationChangedEventArgs e) { Console.WriteLine($"New location: {e.Location}"); // React to navigation StateHasChanged(); } public void Dispose() { Navigation.LocationChanged -= LocationChanged; } } ``` ## Query Strings ### Reading Query Parameters ```csharp @page "/search" @inject NavigationManager Navigation

Search results for: @searchQuery

@code { private string? searchQuery; protected override void OnInitialized() { var uri = Navigation.ToAbsoluteUri(Navigation.Uri); var query = System.Web.HttpUtility.ParseQueryString(uri.Query); searchQuery = query["q"]; } } ``` **Usage:** `/search?q=blazor` → `searchQuery = "blazor"` ### Building Query Strings ```csharp private void Search(string term) { Navigation.NavigateTo($"/search?q={Uri.EscapeDataString(term)}"); } // Or use QueryHelpers (in .NET 6+) var query = new Dictionary { { "q", "blazor" }, { "page", "1" } }; var url = NavigationManager.GetUriWithQueryParameters("/search", query); Navigation.NavigateTo(url); ``` ### Multiple Query Parameters ```csharp var uri = Navigation.ToAbsoluteUri(Navigation.Uri); var query = System.Web.HttpUtility.ParseQueryString(uri.Query); var category = query["category"]; var page = int.TryParse(query["page"], out var p) ? p : 1; var sort = query["sort"] ?? "name"; ``` **Usage:** `/products?category=electronics&page=2&sort=price` ## Router Configuration The Router component in `App.razor` configures routing: ```csharp @pageTitle

Page not found

@code { private List? additionalAssemblies; private string pageTitle = "Loading..."; protected override async Task OnInitializedAsync() { // Load assemblies dynamically if needed additionalAssemblies = new List { typeof(SomeOtherAssembly).Assembly }; } private async Task OnNavigateAsync(NavigationContext context) { // Can be used for lazy loading assemblies // Not commonly needed } } ``` ## Layouts Layouts are parent components that wrap pages. ### Define a Layout ```csharp @inherits LayoutComponentBase
@Header
@Body
@Footer
@code { [Parameter] public RenderFragment? Header { get; set; } [Parameter] public RenderFragment? Navigation { get; set; } [Parameter] public RenderFragment? Body { get; set; } [Parameter] public RenderFragment? Footer { get; set; } } ``` ### Apply Layout to Page ```csharp @page "/products" @layout MainLayout

Products

``` ### Apply Layout to Multiple Pages ```csharp @layout MainLayout ``` Add this line to `_Imports.razor` to apply layout to all components in folder and below. ### Nested Layouts ```csharp @inherits MainLayout @Body ``` ## Page Titles Update page title (browser tab) dynamically: ```csharp @page "/products/{id}" @inject NavigationManager Navigation @title

@title

@code { [Parameter] public string? id { get; set; } private string? title; protected override async Task OnParametersSetAsync() { title = await LoadProductTitleAsync(id); } private async Task LoadProductTitleAsync(string? id) { // Load from service return $"Product {id}"; } } ``` ## Common Routing Patterns ### Master-Detail Pattern ```csharp @page "/products" @page "/products/{id}"
@if (selectedId != null) { }
@code { [Parameter] public string? id { get; set; } private string? selectedId; protected override void OnParametersSet() { selectedId = id; } private void SelectProduct(string productId) { Navigation.NavigateTo($"/products/{productId}"); } } ``` ### Breadcrumb Navigation ```csharp @page "/category/{categoryId}/product/{productId}" @code { [Parameter] public string? categoryId { get; set; } [Parameter] public string? productId { get; set; } private string? categoryName; private string? productName; protected override async Task OnParametersSetAsync() { categoryName = await LoadCategoryAsync(categoryId); productName = await LoadProductAsync(productId); } } ``` ### Tab-Based Navigation ```csharp @page "/settings"
Profile Security Notifications
``` --- **Related Resources:** See [components-lifecycle.md](components-lifecycle.md) for parameter handling. See [authentication-authorization.md](authentication-authorization.md) for route authorization.