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 8 de cet article.

Important

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

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.

Routage statique contre routage interactif

Cette section s’applique aux applications web Blazor.

Si le préréglage n’est pas désactivé, le Blazor routeur (Router composant, <Router> in Routes.razor) effectue un routage statique vers 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 dispositions, consultez Dispositions ASP.NET Core Blazor.

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"

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

Important

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 Héberger et déployer ASP.NET Core Blazor.

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

Depuis le lancement d’ASP.NET Core 5.0.1 et pour les éventuelles versions 5.x supplémentaires, le composant Router comprend le paramètre PreferExactMatches, qui est défini sur @true. Pour plus d’informations, consultez Migrer de ASP.NET Core 3.1 vers 5.0.

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 NotFound du composant Router :

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

Important

Les applications web Blazor n’utilisent pas le paramètre NotFound (<NotFound>...</NotFound>), mais le paramètre est pris en charge pour la compatibilité descendante afin d’éviter un changement cassant dans l’infrastructure. 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. Pour plus d’informations, consultez Modes de rendu ASP.NET Core Blazor.

Effectuer un routage vers les composants à partir de plusieurs assemblys

Cette section s’applique aux applications web Blazor.

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. Appelez la AddAdditionalAssemblies méthode avec les assemblys supplémentaires chaînés MapRazorComponents dans le fichier du projet de Program 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 Router composant hérite du rendu interactif côté serveur (SSR interactif) du Routes composant. 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, un prérendu n’est pas effectué pour les demandes 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="new[] { typeof(BlazorSample.Client._Imports).Assembly }">
    ...
</Router>

Les assemblys supplémentaires sont analysés en plus de l’assembly spécifié dans le cadre de AppAssembly.

Remarque

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

Les composants routables existent également uniquement dans le projet avec le .Client rendu global Interactive WebAssembly ou Auto appliqué, et le Routes composant est défini dans le .Client projet, 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 assemblys supplémentaires sont analysés en plus de l’assembly spécifié dans le cadre de 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}"

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

<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 OnInitialized{Async} est utilisée au lieu de OnParametersSet, 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 depuis /route-parameter-2/amazing. À 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 applique la correspondance de type d’un segment de route par rapport à 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
correspondance
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} CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} Non
int {id:int} 123456789, -123456789 Oui
long {ticks:long} 123456789, -123456789 Oui

Warning

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

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 solutionBlazor WebAssemblyhébergée de router la requête ayant 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 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 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 solutionBlazor WebAssemblyhébergée de router la requête ayant 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 Startup.Configure.

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

@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 Description
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique de fin) qui peut être ajouté au début des 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 la navigation améliorée est disponible à l’URL actuelle, la navigation Blazor améliorée 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é, et aucun nouvel URI n’est envoyé (push) vers 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. L’appel de NavigateTo entraîne toujours l’appel du 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 Description
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique de fin) qui peut être ajouté au début des 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é, et aucun nouvel URI n’est envoyé (push) vers 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. L’appel de NavigateTo entraîne toujours l’appel du 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 Description
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique de fin) qui peut être ajouté au début des 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é, et aucun nouvel URI n’est envoyé (push) vers 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 Description
Uri Obtient l’URI absolu actuel.
BaseUri Obtient l’URI de base (avec une barre oblique de fin) qui peut être ajouté au début des 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"
@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 la suppression de composants, consultez Cycle de vie des composants ASP.NET Core Razor.

Navigation améliorée et gestion des formulaires

Cette section s’applique aux applications web Blazor.

Les applications web Blazor 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’application web Blazor (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 de NavigateTo :

  • Si forceLoad est false, qui est la valeur par défaut :
    • Et la navigation améliorée est disponible à l’URL actuelle, la navigation Blazor améliorée 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 effectue de nouvelles tentatives en tant que chargement de 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 publications de formulaire améliorées fonctionnent uniquement avec les points de terminaison Blazor. La publication d’un formulaire amélioré sur 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 : Remplace 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 peuvent uniquement recevoir des valeurs de paramètre de requête dans les composants routables avec 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é Name de l’attribut [SupplyParameterFromQuery] 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} :

[SupplyParameterFromQuery(Name = "{QUERY PARAMETER NAME}")]
public string? {COMPONENT PARAMETER NAME} { get; set; }
[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]
    public string? Filter { get; set; }

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

    [SupplyParameterFromQuery(Name = "star")]
    public 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 NavigationManager.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 :
    • Si le nom du paramètre de requête n’existe pas dans l’URL actuelle, il est ajouté à la chaîne retournée.
    • Si le paramètre de requête existe dans l’URL actuelle, sa valeur est mise à jour en fonction de la valeur fournie dans la chaîne retournée.
    • Si le type de la valeur fournie est Nullable et si la valeur est null, le paramètre de requête est supprimé de la chaîne retournée.
  • 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 NavigationManager.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 lève 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 lève 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
  • DateTime
  • decimal
  • double
  • float
  • Guid
  • int
  • long
  • string

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 de JS l’interopérabilité, 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é à l’aide des approches suivantes avec une référence de hachage (#) à 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 qui passe 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 un chargement différé d’assemblys dans une application Blazor WebAssembly ou pour une connexion réseau lente à une application Blazor 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 d’un appel 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 OnAfterRender{Async}, où firstRender peut être vérifié. Pour plus d’informations, consultez Prérendu avec l’interopérabilité JavaScript dans l’article Cycle de vie de Blazor.

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, consultez Prérendu avec l’interopérabilité JavaScript dans l’article Cycle de vie de Blazor.

Gérer les annulations dans OnNavigateAsync

L’objet NavigationContext passé au rappel de OnNavigateAsync contient un CancellationToken qui est défini quand 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 ses méthodes OnAfterRender ou OnAfterRenderAsync. 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 le cycle de vie des composants Razor ASP.NET Core.

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. Utilisez le modèle MutationObserver dans JS sur le client. Pour plus d’informations, consultez Interopérabilité JavaScript et ASP.NET Core Blazor (interopérabilité 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 le besoin d’interaction, consultez Fenêtre : événement beforeunload (Documentation MDN).
  • 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> :

Dans l’exemple précédent, HomeNavLinkhref="" correspond à l’URL d’accueil et reçoit uniquement la classe CSS active au niveau du 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).

Des attributs de composant NavLink supplémentaires sont passés à la balise d’ancrage affichée. 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>

Warning

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 = 0; c < 10; c++)
{
    var current = c;
    <li ...>
        <NavLink ... href="product-number/@c">
            <span ...></span> Product #@current
        </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(0,10))
{
    <li ...>
        <NavLink ... href="product-number/@c">
            <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 de composants routables utilisent la casse Pascal†, par exemple Pages/ProductDetail.razor.
  • Les chemins aux fichiers de composant routable correspondent à leurs URL dans le kebab case ‡ avec des tirets apparaissant entre les mots dans le modèle de routage 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()
{
    return 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 Error : la page d’erreur est uniquement redirigée vers l’infrastructure et ne doit pas être répertoriée.

Pour obtenir un exemple de code précédent dans un exemple d’application que vous pouvez exécuter localement, obtenez l’Blazorapplication web ou l’Blazor WebAssemblyexemple d’application.

Intégration du routage de points de terminaison ASP.NET Core

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

Cette section s’applique aux applications Blazor Server.

Une application Web Blazor 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 MapFallbackToPage dans le cadre de l’hébergement de serveurs d’URL non-racines, consultez Héberger et déployer ASP.NET Core Blazor.