Partager via


Navigation ASP.NET Core Blazor

Note

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 10 de cet article.

Avertissement

Cette version d'ASP.NET Core n'est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 10 de cet article.

Cet article explique comment déclencher et gérer la navigation de page dans Blazor. Bien que les utilisateurs puissent naviguer entre différentes pages à l’aide de liens HTML normaux, Blazor améliore la navigation au sein de l’application pour éviter les rechargements de pages complètes et offrir une expérience plus fluide. Utilisez le NavLink composant pour créer des liens de navigation qui appliquent automatiquement le style lorsque le lien correspond à la page active. Pour la navigation programmatique et la gestion des URI dans le code C#, utilisez le NavigationManager service.

Cet article explique comment déclencher et gérer la navigation de page dans Blazor. Utilisez le NavLink composant pour créer des liens de navigation qui appliquent automatiquement le style lorsque le lien correspond à la page active. Pour la navigation programmatique et la gestion des URI dans le code C#, utilisez le NavigationManager service.

Important

Les exemples de code tout au long de cet article illustrent l’appel de méthodes sur Navigation, qui est un NavigationManager injecté dans les classes et les composants.

Utilisez un composant NavLink à la place des éléments de lien hypertexte HTML (<a>) quand vous créez des liens de navigation. Un composant NavLink se comporte comme un élément <a>, à ceci près qu’il ajoute/supprime une classe CSS active selon que son href correspond ou non à l’URL actuelle. La classe active permet à un utilisateur de comprendre quelle est la page active parmi les liens de navigation affichés. Si vous le souhaitez, affectez un nom de classe CSS à NavLink.ActiveClass pour appliquer une classe CSS personnalisée au lien affiché quand la route actuelle correspond à href.

Dans le NavMenu composant (NavMenu.razor) d’une Blazor application créée à partir d’un Blazor modèle de projet :

<div class="nav-item px-3">
    <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
        <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
    </NavLink>
</div>
<div class="nav-item px-3">
    <NavLink class="nav-link" href="counter">
        <span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
    </NavLink>
</div>

Dans l’exemple précédent, le HomeNavLinkhref="" correspond à l’URL d’accueil et reçoit uniquement la classe CSS active sur le chemin de base par défaut de l’application (/). La seconde NavLink reçoit la classe active lorsque l’utilisateur visite le composant Counter à /counter.

Vous pouvez affecter deux options NavLinkMatch à l’attribut Match de l’élément <NavLink> :

  • NavLinkMatch.All: le NavLink est actif lorsqu’il correspond à l’URL actuelle, en ignorant la chaîne de requête et le fragment. Pour inclure la correspondance dans la chaîne/le fragment de requête, veuillez utiliser le commutateur Microsoft.AspNetCore.Components.Routing.NavLink.EnableMatchAllForQueryStringAndFragmentAppContext réglé sur true.
  • NavLinkMatch.Prefix (par défaut) : NavLink est actif quand il correspond à un préfixe de l’URL actuelle.

Pour adopter une logique de correspondance personnalisée, sous-classez NavLink et remplacez sa méthode ShouldMatch. Retournez true de la méthode lorsque vous souhaitez appliquer la classe CSS active :

public class CustomNavLink : NavLink
{
    protected override bool ShouldMatch(string currentUriAbsolute)
    {
        // Custom matching logic
    }
}

Vous pouvez affecter deux options NavLinkMatch à l’attribut Match de l’élément <NavLink> :

  • NavLinkMatch.All: le NavLink est actif lorsqu’il correspond à l’URL actuelle entière, y compris la chaîne de requête et le fragment.
  • NavLinkMatch.Prefix (par défaut) : NavLink est actif quand il correspond à un préfixe de l’URL actuelle.

Des attributs de composant NavLink supplémentaires sont transmis à la balise d’ancrage rendue. Dans l’exemple suivant, le composant NavLink inclut l’attribut target :

<NavLink href="example-page" target="_blank">Example page</NavLink>

Le balisage HTML suivant est affiché :

<a href="example-page" target="_blank">Example page</a>

Avertissement

En raison de la façon dont Blazor affiche le contenu enfant, le rendu des composants NavLink dans une boucle for nécessite une variable d’index local si la variable de boucle d’incrémentation est utilisée dans le contenu du composant (enfant) NavLink :

@for (int c = 1; c < 4; c++)
{
    var ct = c;
    <li ...>
        <NavLink ...>
            <span ...></span> Product #@ct
        </NavLink>
    </li>
}

L’utilisation d’une variable d’index dans ce scénario est obligatoire pour tout composant enfant qui utilise une variable de boucle dans son contenu enfant, et pas seulement le composant NavLink.

Vous pouvez également utiliser une boucle foreach avec Enumerable.Range :

@foreach (var c in Enumerable.Range(1, 3))
{
    <li ...>
        <NavLink ...>
            <span ...></span> Product #@c
        </NavLink>
    </li>
}

Outils d’assistance pour les URI et l’état de navigation

Utilisez NavigationManager pour gérer les URI et la navigation dans du code C#. NavigationManager fournit l’événement et les méthodes indiqués dans le tableau suivant.

Membre Descriptif
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique finale) à ajouter aux chemins d’URI relatifs pour produire un URI absolu. En règle générale, BaseUri correspond à l’attribut href de l’élément <base> du document (emplacement du contenu de <head>).
NavigateTo Permet d’accéder à l’URI spécifié. Si forceLoad a la valeur false :
  • Et une navigation améliorée est disponible à l'URL actuelle, et la navigation améliorée de Blazor est activée.
  • Sinon, Blazor effectue un rechargement de page complète pour l’URL demandée.
Si forceLoad a la valeur true :
  • Le routage côté client est contourné.
  • Le navigateur est forcé de charger la nouvelle page à partir du serveur, que l’URI soit normalement géré ou non par le routeur interactif côté client.

Pour plus d’informations, consultez la section Navigation améliorée et gestion des formulaires.

Si replace a la valeur true, l’URI actuel dans l’historique du navigateur est remplacé au lieu d'ajouter un nouvel URI à la pile de l’historique.

LocationChanged Événement qui se déclenche en cas de changement de l’emplacement de navigation. Pour plus d’informations, consultez la section Changements d’emplacement.
NotFound Appelé pour gérer les scénarios où une ressource demandée n’est pas trouvée. Pour plus d’informations, consultez la section Réponses introuvables .
ToAbsoluteUri Convertit un URI relatif en URI absolu.
ToBaseRelativePath En fonction de l’URI de base de l’application, convertit un URI absolu en URI par rapport au préfixe de l’URI de base. Pour obtenir un exemple, consultez la section Produire un URI par rapport au préfixe de l’URI de base.
RegisterLocationChangingHandler Inscrit un gestionnaire pour traiter les événements de navigation entrants. Appeler NavigateTo déclenche toujours le gestionnaire.
GetUriWithQueryParameter Retourne un URI construit en mettant à jour NavigationManager.Uri via l’ajout, la mise à jour ou la suppression d’un seul paramètre. Pour plus d’informations, consultez la section Chaînes de requête.
Membre Descriptif
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique finale) à ajouter aux chemins d’URI relatifs pour produire un URI absolu. En règle générale, BaseUri correspond à l’attribut href de l’élément <base> du document (emplacement du contenu de <head>).
NavigateTo Permet d’accéder à l’URI spécifié. Si forceLoad a la valeur false :
  • Et une navigation améliorée est disponible à l'URL actuelle, et la navigation améliorée de Blazor est activée.
  • Sinon, Blazor effectue un rechargement de page complète pour l’URL demandée.
Si forceLoad a la valeur true :
  • Le routage côté client est contourné.
  • Le navigateur est forcé de charger la nouvelle page à partir du serveur, que l’URI soit normalement géré ou non par le routeur interactif côté client.

Pour plus d’informations, consultez la section Navigation améliorée et gestion des formulaires.

Si replace a la valeur true, l’URI actuel dans l’historique du navigateur est remplacé au lieu d'ajouter un nouvel URI à la pile de l’historique.

LocationChanged Événement qui se déclenche en cas de changement de l’emplacement de navigation. Pour plus d’informations, consultez la section Changements d’emplacement.
ToAbsoluteUri Convertit un URI relatif en URI absolu.
ToBaseRelativePath En fonction de l’URI de base de l’application, convertit un URI absolu en URI par rapport au préfixe de l’URI de base. Pour obtenir un exemple, consultez la section Produire un URI par rapport au préfixe de l’URI de base.
RegisterLocationChangingHandler Inscrit un gestionnaire pour traiter les événements de navigation entrants. Appeler NavigateTo déclenche toujours le gestionnaire.
GetUriWithQueryParameter Retourne un URI construit en mettant à jour NavigationManager.Uri via l’ajout, la mise à jour ou la suppression d’un seul paramètre. Pour plus d’informations, consultez la section Chaînes de requête.
Membre Descriptif
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique finale) à ajouter aux chemins d’URI relatifs pour produire un URI absolu. En règle générale, BaseUri correspond à l’attribut href de l’élément <base> du document (emplacement du contenu de <head>).
NavigateTo Permet d’accéder à l’URI spécifié. Si forceLoad a la valeur true :
  • Le routage côté client est contourné.
  • Le navigateur est forcé de charger la nouvelle page à partir du serveur, que l’URI soit normalement géré ou non par le routeur côté client.
Si replace a la valeur true, l’URI actuel dans l’historique du navigateur est remplacé au lieu d'ajouter un nouvel URI à la pile de l’historique.
LocationChanged Événement qui se déclenche en cas de changement de l’emplacement de navigation. Pour plus d’informations, consultez la section Changements d’emplacement.
ToAbsoluteUri Convertit un URI relatif en URI absolu.
ToBaseRelativePath En fonction de l’URI de base de l’application, convertit un URI absolu en URI par rapport au préfixe de l’URI de base. Pour obtenir un exemple, consultez la section Produire un URI par rapport au préfixe de l’URI de base.
RegisterLocationChangingHandler Inscrit un gestionnaire pour traiter les événements de navigation entrants. Appeler NavigateTo déclenche toujours le gestionnaire.
GetUriWithQueryParameter Retourne un URI construit en mettant à jour NavigationManager.Uri via l’ajout, la mise à jour ou la suppression d’un seul paramètre. Pour plus d’informations, consultez la section Chaînes de requête.
Membre Descriptif
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique finale) à ajouter aux chemins d’URI relatifs pour produire un URI absolu. En règle générale, BaseUri correspond à l’attribut href de l’élément <base> du document (emplacement du contenu de <head>).
NavigateTo Permet d’accéder à l’URI spécifié. Si forceLoad a la valeur true :
  • Le routage côté client est contourné.
  • Le navigateur est forcé de charger la nouvelle page à partir du serveur, que l’URI soit normalement géré ou non par le routeur côté client.
Si replace a la valeur true, l’URI actuel dans l’historique du navigateur est remplacé au lieu d'ajouter un nouvel URI à la pile de l’historique.
LocationChanged Événement qui se déclenche en cas de changement de l’emplacement de navigation. Pour plus d’informations, consultez la section Changements d’emplacement.
ToAbsoluteUri Convertit un URI relatif en URI absolu.
ToBaseRelativePath En fonction de l’URI de base de l’application, convertit un URI absolu en URI par rapport au préfixe de l’URI de base. Pour obtenir un exemple, consultez la section Produire un URI par rapport au préfixe de l’URI de base.
GetUriWithQueryParameter Retourne un URI construit en mettant à jour NavigationManager.Uri via l’ajout, la mise à jour ou la suppression d’un seul paramètre. Pour plus d’informations, consultez la section Chaînes de requête.
Membre Descriptif
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique finale) à ajouter aux chemins d’URI relatifs pour produire un URI absolu. En règle générale, BaseUri correspond à l’attribut href de l’élément <base> du document (emplacement du contenu de <head>).
NavigateTo Permet d’accéder à l’URI spécifié. Si forceLoad a la valeur true :
  • Le routage côté client est contourné.
  • Le navigateur est forcé de charger la nouvelle page à partir du serveur, que l’URI soit normalement géré ou non par le routeur côté client.
LocationChanged Événement qui se déclenche en cas de changement de l’emplacement de navigation.
ToAbsoluteUri Convertit un URI relatif en URI absolu.
ToBaseRelativePath En fonction de l’URI de base de l’application, convertit un URI absolu en URI par rapport au préfixe de l’URI de base. Pour obtenir un exemple, consultez la section Produire un URI par rapport au préfixe de l’URI de base.

Modifications d’emplacement

Pour l’événement LocationChanged, LocationChangedEventArgs fournit les informations suivantes sur les événements de navigation :

Le composant suivant :

  • Accède au composant Counter (Counter.razor) de l’application quand le bouton est sélectionné à l’aide de NavigateTo.
  • Gère l’événement de changement d’emplacement en s’abonnant à NavigationManager.LocationChanged.
    • La méthode HandleLocationChanged est décrochée quand Dispose est appelé par le framework. Le décrochage de la méthode permet le nettoyage de la mémoire (garbage collection) du composant.

    • L’implémentation du journaliseur entraîne la journalisation des informations suivantes quand le bouton est sélectionné :

      BlazorSample.Pages.Navigate: Information: URL of new location: https://localhost:{PORT}/counter

Navigate.razor :

@page "/navigate"
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate Example</h1>

<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
    Navigate to the Counter component
</button>

@code {
    private void NavigateToCounterComponent() => Navigation.NavigateTo("counter");

    protected override void OnInitialized() => 
        Navigation.LocationChanged += HandleLocationChanged;

    private void HandleLocationChanged(object? sender, LocationChangedEventArgs e) => 
        Logger.LogInformation("URL of new location: {Location}", e.Location);

    public void Dispose() => Navigation.LocationChanged -= HandleLocationChanged;
}

Pour plus d’informations sur l’élimination des composants, consultez Razor élimination de composants.

Pour une redirection pendant le rendu côté serveur statique (SSR statique), NavigationManager s’appuie sur la levée d’un NavigationException élément capturé par l’infrastructure, qui convertit l’erreur en redirection. Code qui existe après l’appel à NavigateTo n’est pas appelé. Lorsque vous utilisez Visual Studio, le débogueur s’arrête sur l’exception, ce qui vous oblige à décocher la case à cocher Lorsque ce type d’exception est géré par l’utilisateur dans l’interface utilisateur de Visual Studio pour éviter l’arrêt du débogueur pour les redirections ultérieures.

Vous pouvez utiliser la <BlazorDisableThrowNavigationException> propriété MSBuild définie sur true dans le fichier projet de l’application pour choisir de ne plus lever de NavigationExceptionfichier . En outre, le code après l’appel à NavigateTo s’exécuter quand il n’aurait pas été exécuté avant. Ce comportement est activé par défaut dans le modèle de projet .NET 10 ou version ultérieure Blazor Web App :

<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>

Note

Dans .NET 10 ou version ultérieure, vous pouvez choisir de ne pas lever d’élément NavigationException en définissant la <BlazorDisableThrowNavigationException> propriété true MSBuild dans le fichier projet de l’application. Pour tirer parti de la nouvelle propriété et du comportement MSBuild, mettez à niveau l’application vers .NET 10 ou version ultérieure.

Réponses introuvables

NavigationManager.NotFound gère les scénarios où une ressource demandée n’est pas trouvée pendant le rendu statique côté serveur (static SSR) ou le rendu interactif global :

  • SSR statique : l’appel NotFound définit le code d’état HTTP sur 404.

  • Rendu interactif : signale au Blazor routeur (Router composant) le rendu du contenu introuvable.

  • Rendu de diffusion en continu : si la navigation améliorée est active, le rendu de streaming affiche le contenu introuvable sans recharger la page. Lorsque la navigation améliorée est bloquée, l’infrastructure redirige vers le contenu introuvable avec une actualisation de page.

Note

La discussion suivante mentionne qu'un composant Introuvable Razor peut être attribué au paramètre Router du composant NotFoundPage. Le paramètre fonctionne de concert avec NotFound et est décrit plus en détail plus loin dans cette section.

Le rendu par streaming peut uniquement rendre des composants qui ont une route, comme une Router.NotFoundPage affectation (NotFoundPage="...") ou une affectation de page Middleware pour la réexécution des pages de code d'état (). DefaultNotFound Le contenu 404 («Not found texte brut ») n’a pas d’itinéraire. Il ne peut donc pas être utilisé pendant le rendu en streaming.

Note

Le fragment de rendu introuvable (<NotFound>...</NotFound>) n’est pas pris en charge dans .NET 10 ou version ultérieure.

NotFound le rendu de contenu utilise les éléments suivants, que la réponse ait démarré ou non (dans l’ordre) :

  • Si NotFoundEventArgs.Path est défini, le contenu de la page affectée est affiché.
  • Si Router.NotFoundPage est défini, affichez la page affectée.
  • Page middleware de réexécution des pages de code de statut, si configurée.
  • Aucune action si aucune des approches précédentes n’est adoptée.

Le middleware de réexécution des pages de code de statut avec UseStatusCodePagesWithReExecute est prioritaire pour les problèmes de routage d’adresse basés sur le navigateur, comme une URL incorrecte saisie dans la barre d’adresse du navigateur ou un clic sur un lien qui n’a pas de point de terminaison dans l’application.

Lorsqu’un composant est rendu statiquement (SSR statique) et NotFound appelé, le code d’état 404 est défini sur la réponse :

@page "/render-not-found-ssr"
@inject NavigationManager Navigation

@code {
    protected override void OnInitialized()
    {
        Navigation.NotFound();
    }
}

Pour fournir du contenu Introuvable pour le rendu interactif global, utilisez une page Introuvable (composant Razor).

Note

Le Blazor modèle de projet inclut une NotFound.razor page. Cette page s’affiche automatiquement chaque fois qu’elle NotFound est appelée, ce qui permet de gérer les itinéraires manquants avec une expérience utilisateur cohérente.

Pages/NotFound.razor :

@page "/not-found"
@layout MainLayout

<h3>Not Found</h3>
<p>Sorry, the content you are looking for does not exist.</p>

Le NotFound composant est affecté à Router.NotFoundPage, qui prend en charge le routage utilisable par l’intergiciel de réexécution des pages de code d’état, y compris ceux qui ne sont pas des intergiciels Blazor.

Dans l’exemple suivant, le composant précédent NotFound est présent dans le dossier de Pages l’application et transmis au NotFoundPage paramètre :

<Router AppAssembly="@typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
</Router>

Lorsqu’un composant est rendu avec un mode de rendu interactif global, l’appel signale NotFound au Blazor routeur le rendu du NotFound composant :

@page "/render-not-found-interactive"
@inject NavigationManager Navigation

@if (RendererInfo.IsInteractive)
{
    <button @onclick="TriggerNotFound">Trigger Not Found</button>
}

@code {
    private void TriggerNotFound()
    {
        Navigation.NotFound();
    }
}

Utilisez l’événement NavigationManager.OnNotFound pour les notifications lorsque NotFound est activé. L’événement est déclenché uniquement lorsqu’il NotFound est appelé, et non pour une réponse 404. Par exemple, régler HttpContextAccessor.HttpContext.Response.StatusCode sur 404 ne déclenche pas NotFound/OnNotFound.

Les applications qui implémentent un routeur personnalisé peuvent également utiliser NotFound. Le routeur personnalisé peut afficher le contenu introuvable à partir de deux sources, en fonction de l’état de la réponse :

  • Quel que soit l’état de réponse, le chemin de réexécution de la page peut être utilisé en le transmettant à UseStatusCodePagesWithReExecute:

    app.UseStatusCodePagesWithReExecute(
        "/not-found", createScopeForStatusCodePages: true);
    
  • Une fois la réponse initiée, NotFoundEventArgs.Path peut être utilisé en s'abonnant à OnNotFoundEvent dans le routeur :

    @code {
        [CascadingParameter]
        public HttpContext? HttpContext { get; set; }
    
        private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
        {
            // Only execute the logic if HTTP response has started,
            // because setting NotFoundEventArgs.Path blocks re-execution
            if (HttpContext?.Response.HasStarted == false)
            {
                return;
            }
    
            var type = typeof(CustomNotFoundPage);
            var routeAttributes = type.GetCustomAttributes<RouteAttribute>(inherit: true);
    
            if (routeAttributes.Length == 0)
            {
                throw new InvalidOperationException($"The type {type.FullName} " +
                    $"doesn't have a {nameof(RouteAttribute)} applied.");
            }
    
            var routeAttribute = (RouteAttribute)routeAttributes[0];
    
            if (routeAttribute.Template != null)
            {
                e.Path = routeAttribute.Template;
            }
        }
    }
    

Dans l’exemple suivant pour les composants qui adoptent le rendu interactif côté serveur (SSR interactif), le contenu personnalisé est rendu en fonction de l’endroit où OnNotFound il est appelé. Si l’événement est déclenché par le composant suivant Movie lorsqu’un film est introuvable sur l’initialisation du composant, un message personnalisé indique que le film demandé n’est pas trouvé. Si l’événement est déclenché par le User composant dans l’exemple suivant, un message différent indique que l’utilisateur n’est pas trouvé.

Le service suivant NotFoundContext gère le contexte et le message pour lequel le contenu n’est pas trouvé par les composants.

NotFoundContext.cs :

public class NotFoundContext
{
    public string? Heading { get; private set; }
    public string? Message { get; private set; }

    public void UpdateContext(string heading, string message)
    {
        Heading = heading;
        Message = message;
    }
}

Le service est inscrit dans le fichier côté Program serveur :

builder.Services.AddScoped<NotFoundContext>();

La page NotFound injecte NotFoundContext et affiche le titre ainsi que le message.

Pages/NotFound.razor :

@page "/not-found"
@layout MainLayout
@inject NotFoundContext NotFoundContext

<h3>@NotFoundContext.Heading</h3>
<div>
    <p>@NotFoundContext.Message</p>
</div>

Le Routes composant (Routes.razor) définit le NotFound composant comme page Introuvable via le NotFoundPage paramètre :

<Router AppAssembly="typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
    ...
</Router>

Dans les exemples de composants suivants :

  • Le NotFoundContext service est injecté, ainsi que le NavigationManager.
  • Dans OnInitializedAsync, HandleNotFound est un gestionnaire d’événements affecté à l’événement OnNotFound . HandleNotFound appels NotFoundContext.UpdateContext pour définir un titre et un message pour le contenu introuvable dans le NotFound composant.
  • Les composants utilisent normalement un ID à partir d’un paramètre de routage pour obtenir un film ou un utilisateur à partir d’un référentiel de données, comme une base de données. Dans les exemples suivants, aucune entité n’est retournée (null) pour simuler ce qui se passe lorsqu’une entité n’est pas trouvée.
  • Lorsqu’aucune entité n’est retournée à OnInitializedAsync, NotFound est appelée, ce qui déclenche à son tour l’événement OnNotFound et le gestionnaire d’événements HandleNotFound. Le contenu introuvable s’affiche par le routeur.
  • La méthode HandleNotFound est désactivée lors de la suppression du composant dans IDisposable.Dispose.

Composant Movie (Movie.razor) :

@page "/movie/{Id:int}"
@implements IDisposable
@inject NavigationManager NavigationManager
@inject NotFoundContext NotFoundContext

<div>
    No matter what ID is used, no matching movie is returned
    from the call to GetMovie().
</div>

@code {
    [Parameter]
    public int Id { get; set; }

    protected override async Task OnInitializedAsync()
    {
        NavigationManager.OnNotFound += HandleNotFound;

        var movie = await GetMovie(Id);

        if (movie == null)
        {
            NavigationManager.NotFound();
        }
    }

    private void HandleNotFound(object? sender, NotFoundEventArgs e)
    {
        NotFoundContext.UpdateContext("Movie Not Found",
            "Sorry! The requested movie wasn't found.");
    }

    private async Task<MovieItem[]?> GetMovie(int id)
    {
        // Simulate no movie with matching id found
        return await Task.FromResult<MovieItem[]?>(null);
    }

    void IDisposable.Dispose()
    {
        NavigationManager.OnNotFound -= HandleNotFound;
    }

    public class MovieItem
    {
        public int Id { get; set; }
        public string? Title { get; set; }
    }
}

Composant User (User.razor) :

@page "/user/{Id:int}"
@implements IDisposable
@inject NavigationManager NavigationManager
@inject NotFoundContext NotFoundContext

<div>
    No matter what ID is used, no matching user is returned
    from the call to GetUser().
</div>

@code {
    [Parameter]
    public int Id { get; set; }

    protected override async Task OnInitializedAsync()
    {
        NavigationManager.OnNotFound += HandleNotFound;

        var user = await GetUser(Id);

        if (user == null)
        {
            NavigationManager.NotFound();
        }
    }

    private void HandleNotFound(object? sender, NotFoundEventArgs e)
    {
        NotFoundContext.UpdateContext("User Not Found",
            "Sorry! The requested user wasn't found.");
    }

    private async Task<UserItem[]?> GetUser(int id)
    {
        // Simulate no user with matching id found
        return await Task.FromResult<UserItem[]?>(null);
    }

    void IDisposable.Dispose()
    {
        NavigationManager.OnNotFound -= HandleNotFound;
    }

    public class UserItem
    {
        public int Id { get; set; }
        public string? Name { get; set; }
    }
}

Pour accéder aux composants précédemment mentionnés dans une démonstration locale avec une application de test, créez des entrées dans le composant NavMenu (NavMenu.razor) pour atteindre les composants Movie et User. Les ID d’entité, passés en tant que paramètres de routage, dans l’exemple suivant sont des valeurs fictives qui n’ont aucun effet, car elles ne sont pas réellement utilisées par les composants, qui simulent ne pas trouver un film ou un utilisateur.

Dans NavMenu.razor :

<div class="nav-item px-3">
    <NavLink class="nav-link" href="movie/1">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Movie
    </NavLink>
</div>

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user/2">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User
    </NavLink>
</div>

Navigation améliorée et gestion des formulaires

Cette section s’applique à Blazor Web App.

Les Blazor Web Apps sont capables de deux types de routage pour la navigation de page et les requêtes de gestion des formulaires :

  • Navigation normale (navigation entre documents) : un rechargement de page complète est déclenché pour l’URL de la requête.
  • Navigation améliorée (navigation dans le même document) : Blazor intercepte la requête et effectue une requête fetch à la place. Blazor corrige ensuite le contenu de la réponse dans le DOM de la page. La navigation Blazor améliorée et la gestion des formulaires évitent d’avoir besoin d’un rechargement de page complète et conservent davantage l’état de la page. Les pages se chargent donc plus rapidement, généralement sans perdre la position de défilement de l’utilisateur sur la page.

La navigation améliorée est disponible lorsque :

  • Le script de l’Blazor Web App (blazor.web.js) est utilisé, et non le script Blazor Server (blazor.server.js) ou le script Blazor WebAssembly (blazor.webassembly.js).
  • La fonctionnalité n’est pas explicitement désactivée.
  • L’URL de destination se trouve dans l’espace d’URI de base interne (chemin d’accès de base de l’application) et le lien vers la page n’a pas l’attribut data-enhance-nav défini sur false.

Si le routage côté serveur et la navigation améliorée sont activés, les gestionnaires de modification d’emplacement sont appelés seulement pour la navigation par programmation lancée depuis un runtime interactif. Dans les prochaines versions, d’autres types de navigation, tels que le suivi d'un lien, pourront également faire appel à des gestionnaires de modification de l'emplacement.

Quand une navigation améliorée se produit, ce sont généralement des gestionnaires d’événements LocationChanged inscrits auprès du serveur interactif et des runtimes WebAssembly qui sont appelés. Il existe des cas où les gestionnaires de modification d’emplacement peuvent ne pas intercepter une navigation améliorée. Par exemple, l’utilisateur peut basculer vers une autre page avant qu’un runtime interactif ne devienne disponible. Par conséquent, il est important que la logique de l’application ne s’appuie pas sur l’appel d’un gestionnaire de modification d’emplacement, car il n’y a pas de garantie qu’un gestionnaire soit en cours d’exécution.

Lors de l'appel NavigateTo :

  • Si forceLoad est false, qui est la valeur par défaut :
    • Et une navigation améliorée est disponible à l'URL actuelle, et la navigation améliorée de Blazor est activée.
    • Sinon, Blazor effectue un rechargement de page complète pour l’URL demandée.
  • Si forceLoad est true : Blazor effectue un rechargement de page complète pour l’URL demandée, que la navigation améliorée soit disponible ou non.

Vous pouvez actualiser la page active en appelant NavigationManager.Refresh(bool forceLoad = false), qui effectue toujours une navigation améliorée, si disponible. Si la navigation améliorée n’est pas disponible, Blazor effectue un rechargement de page complète.

Navigation.Refresh();

Passez true au paramètre forceLoad pour vous assurer qu’un rechargement de page complète est toujours effectué, même si la navigation améliorée est disponible :

Navigation.Refresh(true);

La navigation améliorée est activée par défaut, mais elle peut être contrôlée hiérarchiquement et par lien à l’aide de l’attribut HTML data-enhance-nav.

Les exemples suivants désactivent la navigation améliorée :

<a href="redirect" data-enhance-nav="false">
    GET without enhanced navigation
</a>
<ul data-enhance-nav="false">
    <li>
        <a href="redirect">GET without enhanced navigation</a>
    </li>
    <li>
        <a href="redirect-2">GET without enhanced navigation</a>
    </li>
</ul>

Si la destination est un point de terminaison non-Blazor, la navigation améliorée ne s'applique pas et le JavaScript côté client tente à nouveau de charger une page complète. Cela garantit l’absence de confusion dans l’infrastructure concernant les pages externes qui ne doivent pas être patchées dans une page existante.

Pour activer la gestion améliorée des formulaires, ajoutez le paramètre Enhance aux formulaires EditForm ou l’attribut data-enhance aux formulaires HTML (<form>) :

<EditForm ... Enhance ...>
    ...
</EditForm>
<form ... data-enhance ...>
    ...
</form>

La gestion améliorée des formulaires n’est pas hiérarchique et ne passe pas aux formulaires enfants :

Non pris en charge : vous ne pouvez pas définir la navigation améliorée sur l’élément ancêtre d’un formulaire pour activer la navigation améliorée pour le formulaire.

<div ... data-enhance ...>
    <form ...>
        <!-- NOT enhanced -->
    </form>
</div>

Les formulaires améliorés ne fonctionnent qu'avec des points de terminaison Blazor. L'envoi d'un formulaire amélioré à un point de terminaison non-Blazor entraîne une erreur.

Pour désactiver la navigation améliorée :

  • Pour un EditForm, supprimez le paramètre Enhance de l’élément de formulaire (ou définissez-le sur false : Enhance="false").
  • Pour un code HTML <form>, supprimez l’attribut data-enhance de l’élément de formulaire (ou définissez-le sur false : data-enhance="false").

La navigation améliorée et la gestion des formulaires de Blazor peuvent annuler les modifications dynamiques apportées au DOM si le contenu mis à jour ne fait pas partie du rendu du serveur. Pour conserver le contenu d’un élément, utilisez l’attribut data-permanent.

Dans l’exemple suivant, le contenu de l’élément <div> est mis à jour dynamiquement par un script lorsque la page se charge :

<div data-permanent>
    ...
</div>

Une fois que Blazor a démarré sur le client, vous pouvez utiliser l’évènement enhancedload pour écouter les mises à jour de page améliorées. Cela permet de ré-appliquer les modifications apportées au DOM qui ont peut-être été annulées par une mise à jour de page améliorée.

Blazor.addEventListener('enhancedload', () => console.log('Enhanced update!'));

Pour désactiver globalement la navigation améliorée et la gestion des formulaires, consultez Démarrage de ASP.NET Core Blazor.

La navigation améliorée avec le rendu statique côté serveur (SSR statique) nécessite une attention particulière lors du chargement de JavaScript. Pour plus d’informations, consultez JavaScript Blazor ASP.NET Core avec rendu côté serveur statique (SSR statique).

Produire un URI par rapport au préfixe de l’URI de base

En fonction de l’URI de base de l’application, ToBaseRelativePath convertit un URI absolu en URI par rapport au préfixe de l’URI de base.

Prenons l'exemple suivant :

try
{
    baseRelativePath = Navigation.ToBaseRelativePath(inputURI);
}
catch (ArgumentException ex)
{
    ...
}

Si l’URI de base de l’application est https://localhost:8000, les résultats suivants sont obtenus :

  • Passer https://localhost:8000/segment dans inputURI entraîne un baseRelativePath de segment.
  • Passer https://localhost:8000/segment1/segment2 dans inputURI entraîne un baseRelativePath de segment1/segment2.

Si l’URI de base de l’application ne correspond pas à l’URI de base de inputURI, une ArgumentException est levée.

Passer https://localhost:8001/segment dans inputURI entraîne l’exception suivante :

System.ArgumentException: 'The URI 'https://localhost:8001/segment' is not contained by the base URI 'https://localhost:8000/'.'

Le NavigationManager utilise l’API d’historique du navigateur pour conserver l’état de l’historique de navigation associé à chaque changement d’emplacement effectué par l’application. La conservation de l’état de l’historique est particulièrement utile dans les scénarios de redirection externe, par exemple durant l’authentification des utilisateurs auprès de fournisseurs d’identité externes. Pour plus d’informations, consultez la section Options de navigation.

Passez NavigationOptions à NavigateTo pour contrôler les comportements suivants :

  • ForceLoad : Contourne le routage côté client, et force le navigateur à charger la nouvelle page à partir du serveur, que l’URI soit géré ou non par le routeur côté client. La valeur par défaut est false.
  • ReplaceHistoryEntry : Remplacer l'entrée actuelle dans la pile de l'historique. Si la valeur est false, ajoute la nouvelle entrée à la pile de l’historique. La valeur par défaut est false.
  • HistoryEntryState : Obtient ou définit l’état à ajouter à l’entrée d’historique.
Navigation.NavigateTo("/path", new NavigationOptions
{
    HistoryEntryState = "Navigation state"
});

Pour plus d’informations sur l’obtention de l’état associé à l’entrée d’historique cible durant la gestion des changements d’emplacement, consultez la section Gérer/empêcher les changements d’emplacement.

Chaînes de requête

Utilisez l’attribut [SupplyParameterFromQuery] pour spécifier qu’un paramètre de composant provient de la chaîne de requête.

Utilisez l’attribut [SupplyParameterFromQuery] avec l’attribut [Parameter] pour spécifier qu’un paramètre de composant d’un composant routable provient de la chaîne de requête.

Note

Les paramètres de composant ne peuvent recevoir des valeurs de paramètre de requête que dans des composants routables dotés d'une directive @page.

Seuls les composants routables reçoivent directement les paramètres de requête afin d’éviter de subvertir le flux d’informations descendant et de rendre l’ordre de traitement des paramètres clair, à la fois par l’infrastructure et par l’application. Cette conception évite les bogues subtils dans le code d’application écrit en supposant un ordre de traitement spécifique des paramètres. Vous êtes libre de définir des paramètres en cascade personnalisés ou d’affecter directement des paramètres de composant standard pour passer les valeurs des paramètres de requête aux composants non routables.

Les paramètres de composant fournis à partir de la chaîne de requête prennent en charge les types suivants :

  • bool, DateTime, decimal, double, float, Guid, int, long, string.
  • Variantes Nullable des types précédents.
  • Tableaux des types précédents, qu’il s’agisse ou non de types Nullable.

La mise en forme appropriée, indépendante de la culture, est appliquée pour le type donné (CultureInfo.InvariantCulture).

Spécifiez la propriété [SupplyParameterFromQuery] de l’attribut Name pour utiliser un nom de paramètre de requête différent du nom de paramètre de composant. Dans l’exemple suivant, le nom C# du paramètre de composant est {COMPONENT PARAMETER NAME}. Un autre nom de paramètre de requête est spécifié pour l’espace réservé {QUERY PARAMETER NAME} :

Contrairement aux propriétés des paramètres de composant ([Parameter]), les propriétés [SupplyParameterFromQuery] peuvent être marquées private en plus de public.

[SupplyParameterFromQuery(Name = "{QUERY PARAMETER NAME}")]
private string? {COMPONENT PARAMETER NAME} { get; set; }

Tout comme les propriétés de paramètre de composant ([Parameter]), les propriétés [SupplyParameterFromQuery] sont toujours des propriétés public dans .NET 6/7. Dans .NET 8 ou version ultérieure, les propriétés [SupplyParameterFromQuery] peuvent être marquées public ou private.

[Parameter]
[SupplyParameterFromQuery(Name = "{QUERY PARAMETER NAME}")]
public string? {COMPONENT PARAMETER NAME} { get; set; }

Dans l’exemple suivant avec l’URL /search?filter=scifi%20stars&page=3&star=LeVar%20Burton&star=Gary%20Oldman :

  • La propriété Filter est résolue en scifi stars.
  • La propriété Page est résolue en 3.
  • Le tableau Stars est rempli à partir des paramètres de requête nommés star (Name = "star"), et se résout en LeVar Burton et Gary Oldman.

Note

Les paramètres de chaîne de requête dans le composant de page routable suivant fonctionnent également dans un composant non routable sans directive @page (par exemple, Search.razor pour un composant Search partagé utilisé dans d’autres composants).

Search.razor :

@page "/search"

<h1>Search Example</h1>

<p>Filter: @Filter</p>

<p>Page: @Page</p>

@if (Stars is not null)
{
    <p>Stars:</p>

    <ul>
        @foreach (var name in Stars)
        {
            <li>@name</li>
        }
    </ul>
}

@code {
    [SupplyParameterFromQuery]
    private string? Filter { get; set; }

    [SupplyParameterFromQuery]
    private int? Page { get; set; }

    [SupplyParameterFromQuery(Name = "star")]
    private string[]? Stars { get; set; }
}

Search.razor :

@page "/search"

<h1>Search Example</h1>

<p>Filter: @Filter</p>

<p>Page: @Page</p>

@if (Stars is not null)
{
    <p>Stars:</p>

    <ul>
        @foreach (var name in Stars)
        {
            <li>@name</li>
        }
    </ul>
}

@code {
    [Parameter]
    [SupplyParameterFromQuery]
    public string? Filter { get; set; }

    [Parameter]
    [SupplyParameterFromQuery]
    public int? Page { get; set; }

    [Parameter]
    [SupplyParameterFromQuery(Name = "star")]
    public string[]? Stars { get; set; }
}

Utilisez GetUriWithQueryParameter pour ajouter, changer ou supprimer un ou plusieurs paramètres de requête de l’URL actuelle :

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameter("{NAME}", {VALUE})

Pour l’exemple précédent :

  • L’espace réservé {NAME} spécifie le nom du paramètre de requête. L’espace réservé {VALUE} spécifie la valeur en tant que type pris en charge. Les types pris en charge sont listés plus loin dans cette section.
  • Une chaîne équivalente à l’URL actuelle est retournée avec un seul paramètre :
    • Ajouté si le nom du paramètre de requête n’existe pas dans l’URL actuelle.
    • Mise à jour avec la valeur fournie si le paramètre de requête existe dans l'URL actuelle.
    • Supprimé si le type de la valeur fournie est Nullable et que la valeur est null.
  • La mise en forme appropriée, indépendante de la culture, est appliquée pour le type donné (CultureInfo.InvariantCulture).
  • Le nom et la valeur du paramètre de requête sont codés dans l’URL.
  • Toutes les valeurs portant le nom du paramètre de requête correspondant sont remplacées, s’il existe plusieurs instances du type.

Appelez GetUriWithQueryParameters pour créer un URI construit à partir de Uri avec plusieurs paramètres ajoutés, mis à jour ou supprimés. Pour chaque valeur, le framework utilise value?.GetType() afin de déterminer le type de runtime de chaque paramètre de requête, et sélectionne la mise en forme appropriée, indépendamment de la culture. Le framework génère une erreur pour les types non pris en charge.

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters({PARAMETERS})

L’espace réservé {PARAMETERS} est un IReadOnlyDictionary<string, object>.

Passez une chaîne d’URI à GetUriWithQueryParameters pour générer un nouvel URI à partir d’un URI fourni avec plusieurs paramètres ajoutés, mis à jour ou supprimés. Pour chaque valeur, le framework utilise value?.GetType() afin de déterminer le type de runtime de chaque paramètre de requête, et sélectionne la mise en forme appropriée, indépendamment de la culture. Le framework génère une erreur pour les types non pris en charge. Les types pris en charge sont listés plus loin dans cette section.

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters("{URI}", {PARAMETERS})
  • L’espace réservé {URI} est l’URI avec ou sans chaîne de requête.
  • L’espace réservé {PARAMETERS} est un IReadOnlyDictionary<string, object>.

Les types pris en charge sont identiques aux types pris en charge pour les contraintes de route :

  • bool
  • DateOnly
  • DateTime
  • decimal
  • double
  • float
  • Guid
  • int
  • long
  • string
  • TimeOnly

Les types pris en charge comprennent les suivants :

  • Variantes Nullable des types précédents.
  • Tableaux des types précédents, qu’il s’agisse ou non de types Nullable.

Avertissement

Avec la compression, qui est activée par défaut, évitez de créer des composants côté serveur interactifs (authentifiés/autorisés) sécurisés qui affichent des données en provenance de sources non approuvées. Les sources non approuvées incluent les paramètres de routage, les chaînes de requête, les données issues de l’interopérabilité JS, et toute autre source de données qu’un utilisateur tiers peut contrôler (bases de données, services externes). Pour plus d’informations, consultez Conseils pour ASP.NET Core BlazorSignalR et Conseils d’atténuation des menaces pour le rendu interactif côté serveur de ASP.NET Core Blazor.

Remplacer une valeur de paramètre de requête quand le paramètre existe

Navigation.GetUriWithQueryParameter("full name", "Morena Baccarin")
URL actuelle URL générée
scheme://host/?full%20name=David%20Krumholtz&age=42 scheme://host/?full%20name=Morena%20Baccarin&age=42
scheme://host/?fUlL%20nAmE=David%20Krumholtz&AgE=42 scheme://host/?full%20name=Morena%20Baccarin&AgE=42
scheme://host/?full%20name=Jewel%20Staite&age=42&full%20name=Summer%20Glau scheme://host/?full%20name=Morena%20Baccarin&age=42&full%20name=Morena%20Baccarin
scheme://host/?full%20name=&age=42 scheme://host/?full%20name=Morena%20Baccarin&age=42
scheme://host/?full%20name= scheme://host/?full%20name=Morena%20Baccarin

Ajouter un paramètre de requête et une valeur quand le paramètre n’existe pas

Navigation.GetUriWithQueryParameter("name", "Morena Baccarin")
URL actuelle URL générée
scheme://host/?age=42 scheme://host/?age=42&name=Morena%20Baccarin
scheme://host/ scheme://host/?name=Morena%20Baccarin
scheme://host/? scheme://host/?name=Morena%20Baccarin

Supprimer un paramètre de requête quand la valeur du paramètre est null

Navigation.GetUriWithQueryParameter("full name", (string)null)
URL actuelle URL générée
scheme://host/?full%20name=David%20Krumholtz&age=42 scheme://host/?age=42
scheme://host/?full%20name=Sally%20Smith&age=42&full%20name=Summer%20Glau scheme://host/?age=42
scheme://host/?full%20name=Sally%20Smith&age=42&FuLl%20NaMe=Summer%20Glau scheme://host/?age=42
scheme://host/?full%20name=&age=42 scheme://host/?age=42
scheme://host/?full%20name= scheme://host/

Ajouter, mettre à jour et supprimer des paramètres de requête

Dans l’exemple suivant :

  • name est supprimé, le cas échéant.
  • age est ajouté avec la valeur 25 (int), s’il n’est pas présent. S’il est présent, age est mis à jour avec la valeur 25.
  • eye color est ajouté ou mis à jour avec la valeur green.
Navigation.GetUriWithQueryParameters(
    new Dictionary<string, object?>
    {
        ["name"] = null,
        ["age"] = (int?)25,
        ["eye color"] = "green"
    })
URL actuelle URL générée
scheme://host/?name=David%20Krumholtz&age=42 scheme://host/?age=25&eye%20color=green
scheme://host/?NaMe=David%20Krumholtz&AgE=42 scheme://host/?age=25&eye%20color=green
scheme://host/?name=David%20Krumholtz&age=42&keepme=true scheme://host/?age=25&keepme=true&eye%20color=green
scheme://host/?age=42&eye%20color=87 scheme://host/?age=25&eye%20color=green
scheme://host/? scheme://host/?age=25&eye%20color=green
scheme://host/ scheme://host/?age=25&eye%20color=green

Prise en charge des valeurs énumérables

Dans l’exemple suivant :

  • full name est ajouté ou mis à jour avec Morena Baccarin, une valeur unique.
  • Les paramètres de ping sont ajoutés ou remplacés par 35, 16, 87 et 240.
Navigation.GetUriWithQueryParameters(
    new Dictionary<string, object?>
    {
        ["full name"] = "Morena Baccarin",
        ["ping"] = new int?[] { 35, 16, null, 87, 240 }
    })
URL actuelle URL générée
scheme://host/?full%20name=David%20Krumholtz&ping=8&ping=300 scheme://host/?full%20name=Morena%20Baccarin&ping=35&ping=16&ping=87&ping=240
scheme://host/?ping=8&full%20name=David%20Krumholtz&ping=300 scheme://host/?ping=35&full%20name=Morena%20Baccarin&ping=16&ping=87&ping=240
scheme://host/?ping=8&ping=300&ping=50&ping=68&ping=42 scheme://host/?ping=35&ping=16&ping=87&ping=240&full%20name=Morena%20Baccarin

Pour naviguer avec une chaîne de requête ajoutée ou modifiée, passez une URL générée à NavigateTo.

L’exemple suivant appelle :

  • GetUriWithQueryParameter pour ajouter ou remplacer le paramètre de requête name à l’aide de la valeur Morena Baccarin.
  • Appelle NavigateTo pour déclencher la navigation vers la nouvelle URL.
Navigation.NavigateTo(
    Navigation.GetUriWithQueryParameter("name", "Morena Baccarin"));

La chaîne de requête d’une requête est obtenue à partir de la propriété NavigationManager.Uri :

@inject NavigationManager Navigation

...

var query = new Uri(Navigation.Uri).Query;

Pour analyser les paramètres d’une chaîne de requête, il existe une approche qui consiste à utiliser URLSearchParams avec l’interopérabilité JavaScript (JS) :

export createQueryString = (string queryString) => new URLSearchParams(queryString);

Pour plus d’informations sur l’isolation JavaScript avec des modules JavaScript, consultez Appeler des fonctions JavaScript à partir de méthodes .NET dans ASP.NET Core Blazor.

Accédez à un élément nommé en utilisant les approches suivantes avec une référence hachée (#) à l’élément. Les itinéraires vers des éléments au sein du composant et vers des éléments dans des composants externes utilisent des chemins relatifs à la racine. Une barre oblique de début (/) est facultative.

Les exemples de chacune des approches suivantes illustrent la navigation vers un élément avec un id de targetElement dans le composant Counter :

  • Élément d’ancrage (<a>) avec un href :

    <a href="/counter#targetElement">
    
  • Composant NavLink avec un href :

    <NavLink href="/counter#targetElement">
    
  • NavigationManager.NavigateTo en transmettant l'URL relative :

    Navigation.NavigateTo("/counter#targetElement");
    

L’exemple suivant illustre la navigation vers les en-têtes H2 nommés au sein d’un composant et vers des composants externes.

Dans les composants Home (Home.razor) etCounter (Counter.razor), placez le balisage suivant en bas du balisage de composant existant pour servir de cibles de navigation. Le <div> crée un espace vertical artificiel pour illustrer le comportement de défilement du navigateur :

<div class="border border-info rounded bg-info" style="height:500px"></div>

<h2 id="targetElement">Target H2 heading</h2>
<p>Content!</p>

Ajoutez le composant FragmentRouting suivant à l’application.

FragmentRouting.razor :

@page "/fragment-routing"
@inject NavigationManager Navigation

<PageTitle>Fragment routing</PageTitle>

<h1>Fragment routing to named elements</h1>

<ul>
    <li>
        <a href="/fragment-routing#targetElement">
            Anchor in this component
        </a>
    </li>
    <li>
        <a href="/#targetElement">
            Anchor to the <code>Home</code> component
        </a>
    </li>
    <li>
        <a href="/counter#targetElement">
            Anchor to the <code>Counter</code> component
        </a>
    </li>
    <li>
        <NavLink href="/fragment-routing#targetElement">
            Use a `NavLink` component in this component
        </NavLink>
    </li>
    <li>
        <button @onclick="NavigateToElement">
            Navigate with <code>NavigationManager</code> to the 
            <code>Counter</code> component
        </button>
    </li>
</ul>

<div class="border border-info rounded bg-info" style="height:500px"></div>

<h2 id="targetElement">Target H2 heading</h2>
<p>Content!</p>

@code {
    private void NavigateToElement()
    {
        Navigation.NavigateTo("/counter#targetElement");
    }
}

Gérer/empêcher les changements d’emplacement

RegisterLocationChangingHandler inscrit un gestionnaire pour traiter les événements de navigation entrants. Le contexte du gestionnaire fourni par LocationChangingContext comprend les propriétés suivantes :

Un composant peut inscrire plusieurs gestionnaires de changement d’emplacement dans la méthode de cycle de vie OnAfterRender{Async}. La navigation appelle tous les gestionnaires de changement d’emplacement inscrits dans l’ensemble de l’application (pour plusieurs composants), et la navigation interne les exécute tous en parallèle. Des gestionnaires NavigateTo supplémentaires sont appelés :

  • Au moment de la sélection des liens internes, qui sont des liens pointant vers des URL sous le chemin de base de l’application.
  • Durant la navigation à l’aide des boutons Précédent et Suivant d’un navigateur.

Les gestionnaires sont exécutés uniquement pour la navigation interne au sein de l’application. Si l’utilisateur sélectionne un lien qui lui permet de naviguer vers un autre site, ou s’il change manuellement la barre d’adresse pour accéder à un autre site, les gestionnaires de changement d’emplacement ne sont pas exécutés.

Implémentez IDisposable, et supprimez les gestionnaires inscrits pour les désinscrire. Pour plus d’informations, consultez Suppression de composants ASP.NET Core Razor.

Important

N’essayez pas d’exécuter des tâches de nettoyage DOM via l’interopérabilité JavaScript (JS) quand vous gérez les changements d’emplacement. Utiliser le motif MutationObserver dans JS sur le client. Pour plus d’informations, consultez Interopérabilité JavaScript d'ASP.NET Core Blazor (interop JS).

Dans l’exemple suivant, un gestionnaire de changement d’emplacement est inscrit pour les événements de navigation.

NavHandler.razor :

@page "/nav-handler"
@implements IDisposable
@inject NavigationManager Navigation

<p>
    <button @onclick="@(() => Navigation.NavigateTo("/"))">
        Home (Allowed)
    </button>
    <button @onclick="@(() => Navigation.NavigateTo("/counter"))">
        Counter (Prevented)
    </button>
</p>

@code {
    private IDisposable? registration;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            registration = 
                Navigation.RegisterLocationChangingHandler(OnLocationChanging);
        }
    }

    private ValueTask OnLocationChanging(LocationChangingContext context)
    {
        if (context.TargetLocation == "/counter")
        {
            context.PreventNavigation();
        }

        return ValueTask.CompletedTask;
    }

    public void Dispose() => registration?.Dispose();
}

Dans la mesure où la navigation interne peut être annulée de manière asynchrone, plusieurs appels à des gestionnaires inscrits peuvent se chevaucher. Par exemple, plusieurs appels de gestionnaires peuvent se produire quand l’utilisateur sélectionne rapidement le bouton Précédent sur une page, ou qu’il sélectionne plusieurs liens avant l’exécution d’une navigation. Voici un récapitulatif de la logique de navigation asynchrone :

  • Si des gestionnaires de changement d’emplacement sont inscrits, l’ensemble de la navigation est initialement rétabli, puis relu, si la navigation n’est pas annulée.
  • Si des demandes de navigation se chevauchent, la dernière demande annule toujours les demandes antérieures, ce qui signifie plusieurs choses :
    • L’application peut traiter plusieurs sélections des boutons Précédent et Suivant sous forme d’une seule sélection.
    • Si l’utilisateur sélectionne plusieurs liens avant la fin de la navigation, le dernier lien sélectionné détermine la navigation.

Pour plus d’informations sur le passage de NavigationOptions à NavigateTo pour contrôler les entrées et l’état de la pile de l’historique de navigation, consultez la section Options de navigation.

Pour obtenir un exemple de code supplémentaire, consultez les informations relatives au NavigationManagerComponent dans BasicTestApp (source de référence relative à dotnet/aspnetcore).

Note

Les liens de documentation vers la source de référence .NET chargent généralement la branche par défaut du référentiel, qui représente le développement actuel pour la prochaine version de .NET. Pour sélectionner une balise pour une version spécifique, utilisez la liste déroulante Échanger les branches ou les balises. Pour plus d’informations, consultez Comment sélectionner une balise de version du code source ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Le composant NavigationLock intercepte les événements de navigation tant qu’ils sont affichés, ce qui permet de « verrouiller » efficacement toute navigation donnée jusqu’à ce qu’il soit décidé de la poursuivre ou de l’annuler. Utilisez NavigationLock quand l’interception de la navigation peut être délimitée en fonction de la durée de vie d’un composant.

Paramètres de NavigationLock :

  • ConfirmExternalNavigation définit une boîte de dialogue de navigateur pour inviter l’utilisateur à confirmer ou à annuler la navigation externe. La valeur par défaut est false. L’affichage de la boîte de dialogue de confirmation nécessite une interaction initiale de l’utilisateur avec la page avant de déclencher une navigation externe avec l’URL dans la barre d’adresse du navigateur. Pour plus d’informations sur l’exigence d’interaction, consultez Fenêtre : événement beforeunload.
  • OnBeforeInternalNavigation définit un rappel pour les événements de navigation internes.

Dans le composant NavLock suivant :

NavLock.razor :

@page "/nav-lock"
@inject IJSRuntime JSRuntime
@inject NavigationManager Navigation

<NavigationLock ConfirmExternalNavigation="true" 
    OnBeforeInternalNavigation="OnBeforeInternalNavigation" />

<p>
    <button @onclick="Navigate">Navigate</button>
</p>

<p>
    <a href="https://www.microsoft.com">Microsoft homepage</a>
</p>

@code {
    private void Navigate()
    {
        Navigation.NavigateTo("/");
    }

    private async Task OnBeforeInternalNavigation(LocationChangingContext context)
    {
        var isConfirmed = await JSRuntime.InvokeAsync<bool>("confirm", 
            "Are you sure you want to navigate to the root page?");

        if (!isConfirmed)
        {
            context.PreventNavigation();
        }
    }
}

Pour obtenir un exemple de code supplémentaire, consultez les informations relatives au composant ConfigurableNavigationLock dans BasicTestApp (source de référence relative à dotnet/aspnetcore).

Les entrées de composant NavLink peuvent être créées dynamiquement à partir des composants de l’application via la réflexion. L’exemple suivant illustre l’approche générale pour une personnalisation plus poussée.

Pour la démonstration suivante, une convention d’affectation de noms standard cohérente est utilisée pour les composants de l’application :

  • Les noms de fichiers des composants routables utilisent la casse Pascal†, par exemple Pages/ProductDetail.razor.
  • Les chemins d'accès aux fichiers des composants routables correspondent à leurs URL en majuscules, avec des traits d'union entre les mots dans le modèle de route d'un composant. Par exemple, un composant ProductDetail avec le modèle de routage /product-detail (@page "/product-detail") est demandé dans un navigateur à l’URL relative /product-detail.

†La casse Pascal (casse mixte avec majuscules) est une convention de nommage sans espaces ni ponctuation où la première lettre de chaque mot est en majuscule, y compris le premier mot.
La casse kebab est une convention d’affectation de noms sans espaces et ponctuation qui utilise des lettres minuscules et des tirets entre les mots.

Dans le balisage Razor du composant NavMenu (NavMenu.razor) sous la page Home par défaut, les composants NavLink sont ajoutés à partir d’une collection :

<div class="nav-scrollable" 
    onclick="document.querySelector('.navbar-toggler').click()">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="bi bi-house-door-fill-nav-menu" 
                    aria-hidden="true"></span> Home
            </NavLink>
        </div>

+       @foreach (var name in GetRoutableComponents())
+       {
+           <div class="nav-item px-3">
+               <NavLink class="nav-link" 
+                       href="@Regex.Replace(name, @"(\B[A-Z]|\d+)", "-$1").ToLower()">
+                   @Regex.Replace(name, @"(\B[A-Z]|\d+)", " $1")
+               </NavLink>
+           </div>
+       }

    </nav>
</div>

Méthode GetRoutableComponents dans le bloc @code :

public IEnumerable<string> GetRoutableComponents() => 
    Assembly.GetExecutingAssembly()
        .ExportedTypes
        .Where(t => t.IsSubclassOf(typeof(ComponentBase)))
        .Where(c => c.GetCustomAttributes(inherit: true)
                     .OfType<RouteAttribute>()
                     .Any())
        .Where(c => c.Name != "Home" && c.Name != "Error")
        .OrderBy(o => o.Name)
        .Select(c => c.Name);

L’exemple précédent n’inclut pas les pages suivantes dans la liste des composants affichée :

  • Page Home : la page est répertoriée séparément des liens générés automatiquement, car elle doit apparaître en haut de la liste et définir le paramètre Match.
  • Page d’Error : la page d’erreur n’est accessible que par le framework et ne doit pas être répertoriée.

Pour une démonstration du code précédent dans un exemple d’application, obtenez l'Blazor Web App ou Blazor WebAssembly exemple d’application.