Partager via


Routage et navigation dans ASP.NET Core Blazor

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 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 9 de cet article.

Importante

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 9 de cet article.

Cet article explique comment gérer le routage de requêtes des applications Blazor et comment utiliser le composant NavLink pour créer des liens de navigation.

Importante

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.

Routage statique contre routage interactif

Cette section s’applique à Blazor Web App.

Si le pré-rendu est activé, le Blazor routeur (composant Router, <Router> dans Routes.razor) effectue un routage statique des composants pendant le rendu statique côté serveur (SSR statique). Ce type de routage est appelé routage statique.

Lorsqu’un mode de rendu interactif est attribué au Routes composant, le Blazor routeur devient interactif après le SSR statique avec routage statique sur le serveur. Ce type de routage est appelé routage interactif.

Les routeurs statiques utilisent le routage des points de terminaison et le chemin de requête HTTP pour déterminer le composant à afficher. Lorsque le routeur devient interactif, il utilise l’URL du document (l’URL dans la barre d’adresses du navigateur) pour déterminer le composant à afficher. Cela signifie que le routeur interactif peut changer dynamiquement le composant rendu si l’URL du document change dynamiquement pour une autre URL interne valide, et ce sans effectuer de requête HTTP pour récupérer le nouveau contenu de la page.

Le routage interactif empêche également le prérendu, car le nouveau contenu de la page n’est pas demandé auprès du serveur avec une demande de page normale. Pour plus d’informations, consultez Prévisualiser les composants ASP.NET Core Razor.

Modèles de route

Le composant Router active le routage vers les composants Razor et se trouve dans le composant Routes (Components/Routes.razor) de l’application.

Le composant Router permet d’effectuer un routage vers les composants Razor. Le composant Router est utilisé dans le composant App (App.razor).

Quand un composant Razor (.razor) avec une directive @page est compilé, la classe de composant générée reçoit un RouteAttribute spécifiant le modèle de route du composant.

Au démarrage de l’application, l’assembly spécifié en tant que AppAssembly du routeur est analysé afin de permettre la collecte des informations de route pour les composants de l’application ayant un RouteAttribute.

Au moment de l’exécution, le composant RouteView :

  • Reçoit le RouteData de Router avec tous les paramètres de route.
  • Affiche le composant spécifié avec sa disposition ainsi que toutes les autres dispositions imbriquées.

Spécifiez éventuellement un paramètre DefaultLayout avec une classe de disposition pour les composants qui ne spécifient pas de disposition avec la directive @layout. Les modèles de projet Blazor du framework spécifient le composant MainLayout (MainLayout.razor) en tant que disposition par défaut de l’application. Pour plus d'informations sur les layouts, consultez ASP.NET Core layoutsBlazor.

Les composants prennent en charge plusieurs modèles de route à l’aide de plusieurs directives @page. L’exemple de composant suivant se charge quand /blazor-route et /different-blazor-route sont demandés.

BlazorRoute.razor :

@page "/blazor-route"
@page "/different-blazor-route"

<PageTitle>Routing</PageTitle>

<h1>Routing Example</h1>

<p>
    This page is reached at either <code>/blazor-route</code> or 
    <code>/different-blazor-route</code>.
</p>
@page "/blazor-route"
@page "/different-blazor-route"

<PageTitle>Routing</PageTitle>

<h1>Routing Example</h1>

<p>
    This page is reached at either <code>/blazor-route</code> or 
    <code>/different-blazor-route</code>.
</p>
@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"

<h1>Blazor routing</h1>

Importante

Pour que les URL soient résolues correctement, l’application doit inclure une balise <base> (emplacement du contenu <head>) avec le chemin de base de l’application spécifié dans l’attribut href. Pour plus d’informations, consultez chemin de base de l’application ASP.NET CoreBlazor.

Router n’interagit pas avec les valeurs de chaîne de requête. Pour utiliser des chaînes de requête, consultez la section Chaînes de requête.

Au lieu de spécifier le modèle de route sous forme de littéral de chaîne avec la directive @page, vous pouvez spécifier des modèles de route basés sur des constantes avec la directive @attribute.

Dans l’exemple suivant, la directive @page d’un composant est remplacée par la directive @attribute et le modèle de route basé sur des constantes dans Constants.CounterRoute, qui a la valeur « /counter » ailleurs dans l’application :

- @page "/counter"
+ @attribute [Route(Constants.CounterRoute)]

Remarque

Avec la version .NET 5.0.1 et pour toute version 5.x ultérieure, le composant Router inclut le paramètre PreferExactMatches défini sur @true. Pour plus d’informations, consultez Migrer de ASP.NET Core 3.1 vers .NET 5.

Définir le focus sur un élément dans la navigation

Le composant FocusOnNavigate définit le focus de l’IU sur un élément en fonction d’un sélecteur CSS, après avoir navigué d’une page à une autre.

<FocusOnNavigate RouteData="routeData" Selector="h1" />

Quand le composant Router accède à une nouvelle page, le composant FocusOnNavigate définit le focus sur l’en-tête de premier niveau de la page (<h1>). Il s’agit d’une stratégie courante permettant de garantir l’annonce de la navigation d’une page à une autre en cas d’utilisation d’ un lecteur d’écran.

Fournir du contenu personnalisé quand le contenu est introuvable

Le composant Router permet à l’application de spécifier du contenu personnalisé si le contenu relatif à la route demandée est introuvable.

Définissez du contenu personnalisé pour le paramètre Router du composant NotFound :

<Router ...>
    ...
    <NotFound>
        ...
    </NotFound>
</Router>

Les éléments arbitraires sont pris en charge en tant que contenu du paramètre NotFound, comme d’autres composants interactifs. Pour appliquer une disposition par défaut au contenu NotFound, consultez Dispositions ASP.NET Core Blazor.

Importante

Les Blazor Web App n’utilisent pas le paramètre NotFound (balise <NotFound>...</NotFound>), mais le paramètre est supporté† pour la compatibilité descendante afin d’éviter un changement important dans le framework. Le pipeline intergiciel ASP.NET Core côté serveur traite les requêtes sur le serveur. Utilisez des techniques côté serveur pour traiter les requêtes incorrectes.

pris en charge dans ce contexte signifie que placer une balise <NotFound>...</NotFound> ne résulte pas en une exception, mais utiliser la balise n’est pas non plus efficace.

Pour plus d’informations et une approche recommandée pour gérer les mauvaises requêtes, veuillez consulter ASP.NET Core Blazor modes de rendu.

Effectuer un routage vers les composants à partir de plusieurs assemblys

Cette section s’applique à Blazor Web App.

Utilisez le Router paramètre du composant et le générateur AdditionalAssemblies de conventions de point de terminaison AddAdditionalAssemblies pour découvrir les composants routables dans des assemblys supplémentaires. Les sous-sections suivantes expliquent quand et comment utiliser chaque API.

Routage statique

Pour découvrir des composants routables à partir d’assemblages supplémentaires pour le rendu statique côté serveur (SSR statique), même si le routeur devient ensuite interactif pour le rendu interactif, les assemblages doivent être divulgués à l’infrastructure Blazor. Appeler la méthode AddAdditionalAssemblies avec les assemblages supplémentaires enchaînés à MapRazorComponents dans le fichier Program du projet serveur.

L’exemple suivant inclut les composants routables dans l’assembly BlazorSample.Client du projet à l’aide du fichier du _Imports.razor projet :

app.MapRazorComponents<App>()
    .AddAdditionalAssemblies(typeof(BlazorSample.Client._Imports).Assembly);

Remarque

Les instructions précédentes s’appliquent également dans les scénarios de bibliothèque de classes de composants. Des conseils importants supplémentaires pour les bibliothèques de classes et le SSR statique se trouvent dans ASP.NET Bibliothèques de classes principales Razor (RCL) avec rendu statique côté serveur (SSR statique).

Routage interactif

Un mode de rendu interactif peut être attribué au composant Routes (Routes.razor) pour que le routeur Blazor devienne interactif après le SSR statique et le routage statique sur le serveur. Par exemple, <Routes @rendermode="InteractiveServer" /> attribue un rendu interactif côté serveur (SSR interactif) au Routes composant. Le composant Router hérite du rendu interactif côté serveur (SSR interactif) du composant Routes. Le routeur devient interactif après le routage statique sur le serveur.

La navigation interne pour le routage interactif n’implique pas de demander le nouveau contenu de la page auprès du serveur. Par conséquent, le prérendu ne se produit pas pour les requêtes de pages internes. Pour plus d’informations, consultez Prévisualiser les composants ASP.NET Core Razor.

Si le Routes composant est défini dans le projet serveur, le AdditionalAssemblies paramètre du Router composant doit inclure l’assembly .Client du projet. Cela permet au routeur de fonctionner correctement lorsqu’il est rendu de manière interactive.

Dans l’exemple suivant, le Routes composant se trouve dans le projet serveur et le _Imports.razor fichier du BlazorSample.Client projet indique l’assembly pour rechercher des composants routables :

<Router
    AppAssembly="..."
    AdditionalAssemblies="[ typeof(BlazorSample.Client._Imports).Assembly ]">
    ...
</Router>

Les assemblages supplémentaires sont analysés en plus de l'assemblage spécifié à AppAssembly.

Remarque

Les instructions précédentes s’appliquent également dans les scénarios de bibliothèque de classes de composants.

Par ailleurs, les composants routables n’existent que dans le projet .Client avec le rendu automatique ou WebWassembly interactif global appliqué, et le composant Routes est défini dans le projet .Client, et non dans le projet serveur. Dans ce cas, il n’existe pas d’assemblys externes avec des composants routables. Il n’est donc pas nécessaire de spécifier une valeur pour AdditionalAssemblies.

Cette section s’applique aux applications Blazor Server.

Utilisez le Router paramètre du composant et le générateur AdditionalAssemblies de conventions de point de terminaison AddAdditionalAssemblies pour découvrir les composants routables dans des assemblys supplémentaires.

Dans l’exemple suivant, Component1 est un composant routable défini dans une bibliothèque de classes de composants référencée nommée ComponentLibrary :

<Router
    AppAssembly="..."
    AdditionalAssemblies="new[] { typeof(ComponentLibrary.Component1).Assembly }">
    ...
</Router>

Les assemblages supplémentaires sont analysés en plus de l'assemblage spécifié à AppAssembly.

Paramètres de routage

Le routeur utilise des paramètres de route pour remplir les paramètres de composant correspondants avec le même nom. Les noms de paramètres de route ne respectent pas la casse. Dans l’exemple suivant, le paramètre text affecte la valeur du segment de route à la propriété Text du composant. Lorsqu’une demande est faite pour /route-parameter-1/amazing, le contenu est rendu sous forme de Blazor is amazing!.

RouteParameter1.razor :

@page "/route-parameter-1/{text}"

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

<p>Blazor is @Text!</p>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

<p>Blazor is @Text!</p>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}

Les paramètres facultatifs sont pris en charge. Dans l’exemple suivant, le paramètre facultatif text affecte la valeur du segment de routage à la propriété Text du composant. Si le segment n’est pas présent, la valeur de Text est fantastic.

Les paramètres facultatifs ne sont pas pris en charge. Dans l’exemple suivant, deux directives @page sont appliquées. La première directive permet de naviguer vers le composant sans paramètre. La deuxième directive affecte la valeur du paramètre de route {text} à la propriété Text du composant.

RouteParameter2.razor :

@page "/route-parameter-2/{text?}"

<PageTitle>Route Parameter 2</PageTitle>

<h1>Route Parameter Example 2</h1>

<p>Blazor is @Text!</p>

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

    protected override void OnParametersSet() => Text = Text ?? "fantastic";
}
@page "/route-parameter-2/{text?}"

<PageTitle>Route Parameter 2</PageTitle>

<h1>Route Parameter Example 2</h1>

<p>Blazor is @Text!</p>

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

    protected override void OnParametersSet() => Text = Text ?? "fantastic";
}
@page "/route-parameter-2/{text?}"

<h1>Blazor is @Text!</h1>

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

    protected override void OnParametersSet()
    {
        Text = Text ?? "fantastic";
    }
}
@page "/route-parameter-2/{text?}"

<h1>Blazor is @Text!</h1>

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

    protected override void OnParametersSet()
    {
        Text = Text ?? "fantastic";
    }
}
@page "/route-parameter-2/{text?}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }

    protected override void OnParametersSet()
    {
        Text = Text ?? "fantastic";
    }
}
@page "/route-parameter-2"
@page "/route-parameter-2/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }

    protected override void OnParametersSet()
    {
        Text = Text ?? "fantastic";
    }
}

Lorsque la méthode du cycle de vie OnInitialized{Async} est utilisée au lieu de la méthode du cycle de vie OnParametersSet{Async}, l’affectation par défaut de la propriété Text à fantastic ne se produit pas si l’utilisateur navigue dans le même composant. Par exemple, cette situation se produit lorsque l’utilisateur accède à /route-parameter-2/amazing depuis /route-parameter-2. À mesure que l’instance de composant persiste et accepte de nouveaux paramètres, la méthode OnInitialized n’est pas rappelée.

Remarque

Les paramètres de route ne fonctionnent pas avec les valeurs de chaîne de requête. Pour utiliser des chaînes de requête, consultez la section Chaînes de requête.

Contraintes d'itinéraire

Une contrainte de route impose la correspondance de type d'un segment de route à un composant.

Dans l’exemple suivant, la route vers le composant User correspond uniquement si :

  • Un segment de route Id est présent dans l’URL de requête.
  • Le segment Id est un type entier (int).

User.razor :

@page "/user/{Id:int}"

<PageTitle>User</PageTitle>

<h1>User Example</h1>

<p>User Id: @Id</p>

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

Remarque

Les contraintes de route ne fonctionnent pas avec les valeurs de chaîne de requête. Pour utiliser des chaînes de requête, consultez la section Chaînes de requête.

Les contraintes de route affichées dans le tableau suivant sont disponibles. Si vous souhaitez connaître les contraintes de route qui correspondent à la culture invariante, consultez l’avertissement situé sous le tableau pour plus d’informations.

Contrainte Exemple Exemples de correspondances Invariant
culture
rapprochement
bool {active:bool} true, FALSE Non
datetime {dob:datetime} 2016-12-31, 2016-12-31 7:32pm Oui
decimal {price:decimal} 49.99, -1,000.01 Oui
double {weight:double} 1.234, -1,001.01e8 Oui
float {weight:float} 1.234, -1,001.01e8 Oui
guid {id:guid} 00001111-aaaa-2222-bbbb-3333cccc4444, {00001111-aaaa-2222-bbbb-3333cccc4444} Non
int {id:int} 123456789, -123456789 Oui
long {ticks:long} 123456789, -123456789 Oui
nonfile {parameter:nonfile} Pas BlazorSample.styles.css, pas favicon.ico Oui

Avertissement

Les contraintes de routage qui vérifient que l’URL peut être convertie en type CLR (comme int ou DateTime) utilisent toujours la culture invariant. ces contraintes partent du principe que l’URL n’est pas localisable.

Les contraintes de route fonctionnent également avec les paramètres facultatifs. Dans l’exemple suivant, Id est obligatoire, mais Option est un paramètre de route booléen facultatif.

User.razor :

@page "/user/{id:int}/{option:bool?}"

<p>
    Id: @Id
</p>

<p>
    Option: @Option
</p>

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

    [Parameter]
    public bool Option { get; set; }
}

Éviter la capture de fichiers dans un paramètre de route

Le modèle de route suivant capture par inadvertance les chemins d’accès à la ressource statique dans son paramètre de route facultatif (Optional). Par exemple, la feuille de style de l’application (.styles.css) est capturée, ce qui interrompt les styles de l’application :

@page "/{optional?}"

...

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

Pour restreindre un paramètre de route à la capture des chemins d’accès autres que des fichiers, utilisez la contrainte :nonfile dans le modèle de route :

@page "/{optional:nonfile?}"

Effectuer un routage avec des URL qui contiennent des points

Un modèle de route par défaut côté serveur suppose que si le dernier segment d’une URL de requête contient un point (.), cela signifie qu’un fichier est demandé. Par exemple, l’URL relative /example/some.thing est interprétée par le routeur en tant que requête pour un fichier nommé some.thing. Sans configuration supplémentaire, une application retourne une réponse 404 - Introuvable, si some.thing est destiné à effectuer le routage vers un composant avec une directive @page, et si some.thing est une valeur de paramètre de route. Pour utiliser une route avec un ou plusieurs paramètres qui contiennent un point, l’application doit configurer la route avec un modèle personnalisé.

Prenons comme exemple le composant Example suivant, qui peut recevoir un paramètre de route à partir du dernier segment de l’URL.

Example.razor :

@page "/example/{param?}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string? Param { get; set; }
}
@page "/example/{param?}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string? Param { get; set; }
}
@page "/example/{param?}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string Param { get; set; }
}
@page "/example"
@page "/example/{param}"

<p>
    Param: @Param
</p>

@code {
    [Parameter]
    public string Param { get; set; }
}

Pour permettre à l'application Server d'une solution hébergée Blazor WebAssembly de router la requête avec un point dans le paramètre de route param, ajoutez un modèle de route de fichier de secours avec le paramètre facultatif dans le fichier Program :

app.MapFallbackToFile("/example/{param?}", "index.html");

Pour configurer une application Blazor Server afin de diriger la requête contenant un point dans le paramètre de route param, ajoutez un modèle de route de page de secours avec le paramètre facultatif dans le fichier Program :

app.MapFallbackToPage("/example/{param?}", "/_Host");

Pour plus d’informations, consultez Routage dans ASP.NET Core.

Pour permettre à l'application Server d'une solution hébergée Blazor WebAssembly de router la requête contenant un point dans le paramètre de route param, ajoutez dans Startup.Configure un modèle de route de fichier de secours incluant un paramètre facultatif.

Startup.cs :

endpoints.MapFallbackToFile("/example/{param?}", "index.html");

Pour configurer une application Blazor Server afin de router la requête ayant un point dans le paramètre de route param, ajoutez un modèle de route de page de secours avec le paramètre facultatif dans Startup.Configure.

Startup.cs :

endpoints.MapFallbackToPage("/example/{param?}", "/_Host");

Pour plus d’informations, consultez Routage dans ASP.NET Core.

Paramètres de route fourre-tout

Les paramètres de route fourre-tout, qui capturent les chemins au-delà de plusieurs limites de dossiers, sont pris en charge dans les composants.

Les paramètres de route fourre-tout sont :

  • Nommés pour correspondre au nom du segment de route. Le nommage ne respecte pas la casse.
  • Type string. Le framework ne fournit pas de cast automatique.
  • À la fin de l’URL.

CatchAll.razor :

@page "/catch-all/{*pageRoute}"

<PageTitle>Catch All</PageTitle>

<h1>Catch All Parameters Example</h1>

<p>Add some URI segments to the route and request the page again.</p>

<p>
    PageRoute: @PageRoute
</p>

@code {
    [Parameter]
    public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"

<PageTitle>Catch All</PageTitle>

<h1>Catch All Parameters Example</h1>

<p>Add some URI segments to the route and request the page again.</p>

<p>
    PageRoute: @PageRoute
</p>

@code {
    [Parameter]
    public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"

@code {
    [Parameter]
    public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"

@code {
    [Parameter]
    public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"

@code {
    [Parameter]
    public string PageRoute { get; set; }
}

Pour l’URL /catch-all/this/is/a/test avec le modèle de route /catch-all/{*pageRoute}, la valeur de PageRoute est this/is/a/test.

Les barres obliques et les segments du chemin capturé sont décodés. Pour le modèle de route /catch-all/{*pageRoute}, l’URL /catch-all/this/is/a%2Ftest%2A donne this/is/a/test*.

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

<PageTitle>Navigate</PageTitle>

<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;
}
@page "/navigate"
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<PageTitle>Navigate</PageTitle>

<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;
}
@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code 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;
    }
}
@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code 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;
    }
}
@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code 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;
    }
}
@page "/navigate"
@using Microsoft.Extensions.Logging 
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation

<h1>Navigate in component code 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.

Réponses introuvables

Dans .NET 10 Preview 4, les réponses introuvables sont disponibles uniquement pour le rendu côté serveur statique et le rendu interactif global. La prise en charge du rendu par page/composant est prévue pour la préversion 5 en juin 2025.

NavigationManager fournit une NotFound méthode pour gérer les scénarios où une ressource demandée n’est pas trouvée pendant le rendu côté serveur statique (SSR statique) ou le rendu interactif global :

  • SSR statique : l’appel NotFound définit le code d’état HTTP sur 404.
  • Rendu en streaming : lève une exception si la réponse a déjà démarré.
  • Rendu interactif : signale au Blazor routeur (Router composant) le rendu du contenu introuvable.

Lorsqu’un composant est rendu statiquement (SSR statique) et NavigationManager.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).

Remarque

Le Blazor modèle de projet inclut une NotFound.razor page par défaut. Cette page s’affiche automatiquement chaque fois qu’elle NavigationManager.NotFound est appelée, ce qui facilite la gestion des itinéraires manquants avec une expérience utilisateur cohérente.

NotFound.razor :

<h1>Not Found</h1>

<p>Sorry! Nothing to show.</p>

Affectez le NotFound composant au paramètre du NotFoundPage routeur. NotFoundPage prend en charge le routage qui peut être utilisé à travers des middleware de réexécution, y compris ceux qui ne sont pas basés sur Blazor. Si le fragment de NotFound rendu est défini avec NotFoundPage, la page a une priorité plus élevée.

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();
    }
}

Vous pouvez utiliser l'événement OnNotFound pour les notifications lorsqu'il NotFound est invoqué. 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.

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, 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; } = "Not Found";
    public string Message { get; private set; } = 
        "Sorry, the page that you requested couldn't be found.";

    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>();

Le composant Routes (Routes.razor) :

  • Injecte le service NotFoundContext.
  • Affiche le titre (Heading) et le message (Message) lorsque OnNotFound est déclenché par un appel à NotFound.
@inject NotFoundContext NotFoundContext

<Router AppAssembly="typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
        <FocusOnNavigate RouteData="routeData" Selector="h1" />
    </Found>
    <NotFound>
        <LayoutView Layout="typeof(Layout.MainLayout)">
            <h1>@NotFoundContext.Heading</h1> 
            <div>
                <p>@NotFoundContext.Message</p>
            </div>
        </LayoutView>
    </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 appelle NotFoundContext.UpdateContext pour définir un titre et un message pour le contenu introuvable affiché par le composant Router dans le composant Routes (Routes.razor).
  • 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, NavigationManager.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étachée lors de la suppression des composants 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).

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 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.

Remarque

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, floatintlongdoubleGuid, . 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.

Remarque

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.

Routage haché vers des éléments nommés

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 le routage haché vers des 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 HashedRouting suivant à l’application.

HashedRouting.razor :

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

<PageTitle>Hashed routing</PageTitle>

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

<ul>
    <li>
        <a href="/hashed-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="/hashed-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");
    }
}

Interaction utilisateur avec du contenu <Navigating>

S’il existe un délai important pendant la navigation, par exemple pendant le chargement différé d’assemblages dans une application Blazor WebAssembly ou pour une connexion réseau lente à une application Blazor sur le côté serveur, le composant Router peut indiquer à l’utilisateur qu’une transition de page se produit.

En haut du composant qui spécifie le composant Router, ajoutez une directive @using pour l’espace de noms Microsoft.AspNetCore.Components.Routing :

@using Microsoft.AspNetCore.Components.Routing

Fournissez du contenu au paramètre Navigating à afficher lors des événements de transition de page.

Dans le contenu de l’élément routeur (<Router>...</Router>) :

<Navigating>
    <p>Loading the requested page&hellip;</p>
</Navigating>

Pour obtenir un exemple qui utilise la propriété Navigating, consultez Charger des assemblys en mode différé dans ASP.NET Core Blazor WebAssembly.

Gérer les événements de navigation asynchrones avec OnNavigateAsync

Le composant Router prend en charge une fonctionnalité OnNavigateAsync. Le gestionnaire OnNavigateAsync est appelé quand l’utilisateur :

  • Visite une route pour la première fois en y accédant directement dans son navigateur.
  • Accède à une nouvelle route à l’aide d’un lien ou par une invocation de NavigationManager.NavigateTo.
<Router AppAssembly="typeof(App).Assembly" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext args)
    {
        ...
    }
}
<Router AppAssembly="typeof(Program).Assembly" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext args)
    {
        ...
    }
}

Pour obtenir un exemple qui utilise OnNavigateAsync, consultez Charger des assemblys en mode différé dans ASP.NET Core Blazor WebAssembly.

En cas de prérendu sur le serveur, OnNavigateAsync est exécuté deux fois :

  • Une première fois quand le composant de point de terminaison demandé est affiché initialement de manière statique.
  • Une deuxième fois quand le navigateur affiche le composant de point de terminaison.

Pour empêcher le code de développeur dans OnNavigateAsync de s’exécuter à deux reprises, le composant Routes peut stocker le NavigationContext afin de l’utiliser dans la méthode du cycle de vie OnAfterRender{Async}, où firstRender peut être vérifié. Pour plus d'informations, voir Prérendu avec JavaScript interop.

Pour empêcher le code de développeur dans OnNavigateAsync de s’exécuter à deux reprises, le composant App peut stocker le NavigationContext afin de l’utiliser dans OnAfterRender{Async}, où firstRender peut être vérifié. Pour plus d'informations, voir Prérendu avec JavaScript interop.

Gérer les annulations dans OnNavigateAsync

L’objet NavigationContext passé à la fonction de rappel de OnNavigateAsync contient un CancellationToken qui est attribué lorsqu'un nouvel événement de navigation se produit. Le rappel de OnNavigateAsync doit lever une exception au moment où ce jeton d’annulation est défini pour éviter de poursuivre l’exécution du rappel de OnNavigateAsync en cas de navigation obsolète.

Si un utilisateur accède à un point de terminaison, puis accède immédiatement après à un nouveau point de terminaison, l’application ne doit pas continuer à exécuter le rappel de OnNavigateAsync pour le premier point de terminaison.

Dans l’exemple suivant :

  • Le jeton d’annulation est passé dans l’appel à PostAsJsonAsync, qui peut annuler la méthode POST si l’utilisateur quitte le point de terminaison /about.
  • Le jeton d’annulation est défini durant une opération de prérécupération du produit si l’utilisateur quitte le point de terminaison /store.
@inject HttpClient Http
@inject ProductCatalog Products

<Router AppAssembly="typeof(App).Assembly" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext context)
    {
        if (context.Path == "/about") 
        {
            var stats = new Stats { Page = "/about" };
            await Http.PostAsJsonAsync("api/visited", stats, 
                context.CancellationToken);
        }
        else if (context.Path == "/store")
        {
            var productIds = new[] { 345, 789, 135, 689 };

            foreach (var productId in productIds) 
            {
                context.CancellationToken.ThrowIfCancellationRequested();
                Products.Prefetch(productId);
            }
        }
    }
}
@inject HttpClient Http
@inject ProductCatalog Products

<Router AppAssembly="typeof(Program).Assembly" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext context)
    {
        if (context.Path == "/about") 
        {
            var stats = new Stats { Page = "/about" };
            await Http.PostAsJsonAsync("api/visited", stats, 
                context.CancellationToken);
        }
        else if (context.Path == "/store")
        {
            var productIds = new[] { 345, 789, 135, 689 };

            foreach (var productId in productIds) 
            {
                context.CancellationToken.ThrowIfCancellationRequested();
                Products.Prefetch(productId);
            }
        }
    }
}

Remarque

Le fait de ne pas lever d’exception si le jeton d’annulation dans NavigationContext est annulé peut entraîner un comportement involontaire, par exemple le rendu d’un composant à partir d’une navigation précédente.

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.

Importante

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).

Remarque

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).

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.

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.

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.

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 (/). Le deuxième NavLink reçoit la classe active quand l’utilisateur visite une URL ayant un préfixe component (par exemple /component et /component/another-segment).

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
    }
}

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>
}

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 obtenir un exemple du code ci-dessus dans une application d'exemple que vous pouvez exécuter localement, téléchargez l’exemple d’application Blazor Web App ou Blazor WebAssembly.

Intégration du routage d'endpoint ASP.NET Core

Cette section s’applique aux Blazor Web Apps fonctionnant sur un circuit.

Cette section s’applique aux applications Blazor Server.

Une Blazor Web App est intégrée au routage de points de terminaison ASP.NET Core. Une application ASP.NET Core est configurée pour accepter les connexions entrantes des composants interactifs avec MapRazorComponents dans le fichier Program. Le composant racine par défaut (premier composant chargé) est le composant App (App.razor) :

app.MapRazorComponents<App>();

Blazor Server est intégré au routage de points de terminaison ASP.NET Core. Une application ASP.NET Core est configurée pour accepter les connexions entrantes des composants interactifs avec MapBlazorHub dans le fichier Program :

app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

Blazor Server est intégré au routage de points de terminaison ASP.NET Core. Une application ASP.NET Core est configurée pour accepter les connexions entrantes des composants interactifs avec MapBlazorHub dans Startup.Configure.

La configuration classique consiste à router toutes les requêtes vers une page Razor, qui sert d’hôte côté serveur de l’application Blazor Server. Par convention, la page hôte est généralement nommée _Host.cshtml dans le dossier Pages de l’application.

La route spécifiée dans le fichier hôte est appelée route de secours, car elle fonctionne avec une basse priorité dans la mise en correspondance des routes. La route de secours est utilisée quand les autres routes ne correspondent pas. Cela permet à l’application d’utiliser d’autres contrôleurs et pages sans interférer avec le routage des composants dans l’application Blazor Server.

Pour plus d’informations sur la configuration de l’hébergement de serveur pour une URL non principale, consultez< c2>le chemin d'accès de base de l'application ASP.NET Core.