Enrutamiento de Blazor de ASP.NET Core
En este artículo, aprenderá a administrar el enrutamiento de solicitudes y a usar el componente NavLink para crear vínculos de navegación en aplicaciones de Blazor.
Plantillas de ruta
El componente Router habilita el enrutamiento a componentes Razor en una aplicación de Blazor. El componente Router se usa en el componente App de aplicaciones de Blazor.
App.razor:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<p>Sorry, there's nothing at this address.</p>
</NotFound>
</Router>
Cuando se compila un componente Razor (.razor) con una directiva @page, la clase de componente generada recibe un elemento RouteAttribute que especifica la plantilla de ruta del componente.
Cuando se inicia la aplicación, el ensamblado especificado como AppAssembly del enrutador se examina para recopilar información de ruta de los componentes de la aplicación que tienen un elemento RouteAttribute.
En tiempo de ejecución, el componente RouteView:
- Recibe el elemento RouteData de Router junto con los parámetros de ruta.
- Representa el componente especificado con su diseño, incluidos los diseños anidados adicionales.
Opcionalmente, se puede especificar un parámetro DefaultLayout con una clase de diseño para los componentes que no tengan especificado un diseño con la directiva @layout. Las plantillas de proyecto de Blazor del marco especifican el componente MainLayout (Shared/MainLayout.razor) como diseño predeterminado de la aplicación. Para más información sobre los diseños, vea Diseños de ASP.NET Core Blazor.
Los componentes admiten varias plantillas de ruta mediante varias directivas @page. El componente de ejemplo siguiente se carga en las solicitudes de /BlazorRoute y /DifferentBlazorRoute.
Pages/BlazorRoute.razor:
@page "/BlazorRoute"
@page "/DifferentBlazorRoute"
<h1>Blazor routing</h1>
Importante
Para que las direcciones URL se resuelvan correctamente, la aplicación debe incluir una etiqueta <base> en su archivo wwwroot/index.html (Blazor WebAssembly) o en su archivo Pages/_Layout.cshtml (Blazor Server) con la ruta de acceso base de la aplicación especificada en el atributo href. Para obtener más información, vea Hospedaje e implementación de ASP.NET Core Blazor.
Foco en un elemento de la navegación
Use el componente FocusOnNavigate para establecer el foco de la interfaz de usuario en un elemento basado en un selector CSS después de navegar de una página a otra. Puede ver que el componente FocusOnNavigate se usa en el componente App de una aplicación generada a partir de una plantilla de proyecto Blazor.
App.razor:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
Cuando el componente Router anterior navega a una página nueva, el componente FocusOnNavigate establece el foco en el encabezado de nivel superior de la página (<h1>). Se trata de una estrategia común para asegurarse de que se anuncian las navegaciones de página cuando se usa un lector de pantalla.
Suministro de contenido personalizado cuando no se encuentra contenido
El componente Router permite a la aplicación especificar contenido personalizado si no se encuentra contenido para la ruta solicitada.
En el componente App, establezca el contenido personalizado en la plantilla NotFound del componente Router.
App.razor:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<h1>Sorry</h1>
<p>Sorry, there's nothing at this address.</p> b
</NotFound>
</Router>
Los elementos arbitrarios se admiten como contenido de las etiquetas <NotFound>, como otros componentes interactivos. Para aplicar un diseño predeterminado al contenido de NotFound, vea Diseños de ASP.NET Core Blazor.
Ruta a componentes desde varios ensamblados
Use el parámetro AdditionalAssemblies para especificar más ensamblados para que el componente Router los tenga en cuenta al buscar componentes enrutables. Se examinan los ensamblados adicionales, además del ensamblado especificado para AppAssembly. En el siguiente ejemplo, Component1 es un componente enrutable definido en una biblioteca de clases de componentes a la que se hace referencia. El siguiente ejemplo de AdditionalAssemblies da como resultado una compatibilidad de enrutamiento con Component1.
App.razor:
<Router
AppAssembly="@typeof(Program).Assembly"
AdditionalAssemblies="new[] { typeof(Component1).Assembly }">
@* ... Router component elements ... *@
</Router>
Parámetros de ruta
El enrutador usa parámetros de ruta para rellenar los parámetros de componente correspondientes con el mismo nombre. Los nombres de parámetros de ruta no distinguen mayúsculas de minúsculas. En el ejemplo siguiente, el parámetro text asigna el valor del segmento de ruta a la propiedad Text del componente. Cuando se realiza una solicitud de /RouteParameter/amazing, el contenido de la etiqueta <h1> se representa como Blazor is amazing!.
Pages/RouteParameter.razor:
@page "/RouteParameter/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
}
Se admiten parámetros opcionales. En el ejemplo siguiente, el parámetro opcional text asigna el valor del segmento de ruta a la propiedad Text del componente. Si el segmento no está presente, el valor de Text se establece en fantastic.
Pages/RouteParameter.razor:
@page "/RouteParameter/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnInitialized()
{
Text = Text ?? "fantastic";
}
}
Use OnParametersSet, en lugar de OnInitialized{Async}, para permitir la navegación de la aplicación al mismo componente con un valor de parámetro opcional diferente. Según el ejemplo anterior, use OnParametersSet cuando el usuario pueda navegar desde /RouteParameter a /RouteParameter/amazing, o desde /RouteParameter/amazing a /RouteParameter:
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
Restricciones de ruta
Una restricción de ruta fuerza la coincidencia de tipos en un segmento de ruta a un componente.
En el siguiente ejemplo, la ruta al componente User solo coincide en estos casos:
- Existe un segmento de ruta
Iden la dirección URL de la solicitud. - El segmento
Ides un tipo de entero (int).
Pages/User.razor:
@page "/user/{Id:int}"
<h1>User Id: @Id</h1>
@code {
[Parameter]
public int Id { get; set; }
}
En la siguiente tabla figuran las restricciones de ruta que hay disponibles. Para más información sobre las restricciones de ruta que coinciden con la referencia cultural invariable, consulte la advertencia que aparece después de la tabla.
| Restricción | Ejemplo | Coincidencias de ejemplo | Invariable referencia cultural coincidencia |
|---|---|---|---|
bool |
{active:bool} |
true, FALSE |
No |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Sí |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Sí |
double |
{weight:double} |
1.234, -1,001.01e8 |
Sí |
float |
{weight:float} |
1.234, -1,001.01e8 |
Sí |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} |
No |
int |
{id:int} |
123456789, -123456789 |
Sí |
long |
{ticks:long} |
123456789, -123456789 |
Sí |
Advertencia
Las restricciones de ruta que comprueban la dirección URL y que se convierten en un tipo CLR (como int o DateTime) usan siempre la referencia cultural invariable. Estas restricciones dan por supuesto que la dirección URL no es localizable.
Las restricciones de ruta también funcionan con parámetros opcionales. En el ejemplo siguiente, Id es obligatorio, pero Option es un parámetro de ruta booleano opcional.
Pages/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; }
}
Enrutamiento con direcciones URL que contienen puntos
En el caso de las aplicaciones hospedadas de Blazor WebAssembly y Blazor Server, la plantilla de ruta predeterminada del lado servidor presupone que, si el último segmento de una dirección URL de solicitud contiene un punto (.), se solicita un archivo. Por ejemplo, el enrutador interpreta la dirección URL https://localhost.com:5001/example/some.thing como una solicitud de un archivo denominado some.thing. Sin configuración adicional, una aplicación devuelve una respuesta 404: no encontrado si se pretendía enrutar some.thing a un componente con una directiva @page y some.thing es un valor de parámetro de ruta. Para usar una ruta con uno o más parámetros que contengan un punto, la aplicación debe configurar la ruta con una plantilla personalizada.
Tenga en cuenta el siguiente componente Example que puede recibir un parámetro de ruta del último segmento de la dirección URL.
Pages/Example.razor:
@page "/example/{param?}"
<p>
Param: @Param
</p>
@code {
[Parameter]
public string? Param { get; set; }
}
Para permitir que la aplicación Server de una solución de Blazor WebAssembly hospedada enrute la solicitud con un punto en el parámetro de ruta param, agregue una plantilla de ruta de archivo de reserva con el parámetro opcional en Program.cs:
app.MapFallbackToFile("/example/{param?}", "index.html");
Para configurar una aplicación Blazor Server para enrutar la solicitud con un punto en el parámetro de ruta param, agregue una plantilla de ruta de página de reserva con el parámetro opcional en Program.cs:
app.MapFallbackToPage("/example/{param?}", "/_Host");
Para obtener más información, vea Enrutamiento en ASP.NET Core.
Parámetros de ruta de captura general
Los parámetros de ruta de captura general, que capturan rutas de acceso en varios límites de carpeta, se admiten en los componentes.
Los parámetros de ruta de captura general son:
- Con nombre para que coincida con el nombre del segmento de ruta. La nomenclatura no distingue mayúsculas de minúsculas.
- Tipo
string. El marco no proporciona conversión automática. - Al final de la dirección URL.
Pages/CatchAll.razor:
@page "/catch-all/{*pageRoute}"
@code {
[Parameter]
public string? PageRoute { get; set; }
}
Para la dirección URL /catch-all/this/is/a/test con una plantilla de ruta de /catch-all/{*pageRoute}, el valor de PageRoute se establece en this/is/a/test.
Las barras diagonales y los segmentos de la ruta de acceso capturada están descodificados. En el caso de una plantilla de ruta de /catch-all/{*pageRoute}, la dirección URL /catch-all/this/is/a%2Ftest%2A produce this/is/a/test*.
Aplicaciones auxiliares de URI y estado de navegación
Use NavigationManager para administrar los URI y la navegación en el código de C#. NavigationManager proporciona el evento y los métodos que se muestran en la siguiente tabla.
| Miembro | Descripción |
|---|---|
| Uri | Obtiene el URI absoluto actual. |
| BaseUri | Obtiene el URI base (con una barra diagonal final) que se puede anteponer a las rutas de acceso de URI relativo para generar un URI absoluto. Normalmente, BaseUri corresponde al atributo href del elemento <base> del documento en wwwroot/index.html (Blazor WebAssembly) o Pages/_Layout.cshtml (Blazor Server). |
| NavigateTo | Navega al URI especificado. Si forceLoad es true:
replace es true, el URI actual en el historial del explorador se reemplaza en lugar de insertar un URI nuevo en la pila del historial. |
| LocationChanged | Evento que se desencadena cuando la ubicación de navegación ha cambiado. Para obtener más información, vea la sección Cambios de ubicación. |
| ToAbsoluteUri | Convierte un URI relativo en un URI absoluto. |
| ToBaseRelativePath | Dado un URI base (por ejemplo, un URI previamente devuelto por BaseUri), convierte un URI absoluto en un URI relativo al prefijo de URI base. |
GetUriWithQueryParameter |
Devuelve un URI construido mediante la actualización de NavigationManager.Uri con un único parámetro agregado, actualizado o quitado. Para obtener más información, vea la sección Cadenas consulta. |
Cambios de ubicación
En el caso del evento LocationChanged, LocationChangedEventArgs proporciona la información siguiente sobre los eventos de navegación:
- Location: la dirección URL de la nueva ubicación.
- IsNavigationIntercepted: si es
true, Blazor ha interceptado la navegación del explorador. Sifalse, NavigationManager.NavigateTo hizo que se produjera la navegación.
El siguiente componente:
- Navega al componente
Counterde la aplicación (Pages/Counter.razor) cuando se selecciona el botón con NavigateTo. - Controla el evento de ubicación cambiado mediante la suscripción a NavigationManager.LocationChanged.
El método
HandleLocationChangedse desenlaza cuando el marco llama aDispose. Al desenlazar el método se permite la recolección de elementos no utilizados del componente.La implementación del registrador registra la siguiente información cuando se selecciona el botón:
BlazorSample.Pages.Navigate: Information: URL of new location: https://localhost:5001/counter
Pages/Navigate.razor:
@page "/navigate"
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager NavigationManager
<h1>Navigate in component code example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent()
{
NavigationManager.NavigateTo("counter");
}
protected override void OnInitialized()
{
NavigationManager.LocationChanged += HandleLocationChanged;
}
private void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
{
Logger.LogInformation("URL of new location: {Location}", e.Location);
}
public void Dispose()
{
NavigationManager.LocationChanged -= HandleLocationChanged;
}
}
Para obtener más información sobre la eliminación de componentes, vea Ciclo de vida de los componentes de ASP.NET Core Razor.
Cadenas de consulta
Use el atributo [SupplyParameterFromQuery] con el atributo [Parameter] para especificar que un parámetro de componente de un componente enrutable puede proceder de la cadena de consulta.
Nota
Los parámetros de componente solo pueden recibir valores de parámetro de consulta en componentes enrutables con una directiva @page.
Los parámetros de componente proporcionados a partir de la cadena de consulta admiten los tipos siguientes:
bool,DateTime,decimal,double,float,Guid,int,long,string.- Variantes que admiten un valor NULL de los tipos anteriores (excepto
string, que no tiene una de esas variantes). - Matrices de los tipos anteriores, con independencia de que admitan un valor NULL o no.
El formato de referencia cultural invariable correcto se aplica al tipo especificado (CultureInfo.InvariantCulture).
Especifique la propiedad Name del atributo [SupplyParameterFromQuery] para usar un nombre de parámetro de consulta diferente al nombre del parámetro de componente. En el ejemplo siguiente, el nombre en C# del parámetro de componente es {COMPONENT PARAMETER NAME}. Se especifica otro nombre de parámetro de consulta para el marcador de posición {QUERY PARAMETER NAME}:
[Parameter]
[SupplyParameterFromQuery(Name = "{QUERY PARAMETER NAME}")]
public string {COMPONENT PARAMETER NAME} { get; set; }
En el ejemplo siguiente con una dirección URL de /search?filter=scifi%20stars&page=3&star=LeVar%20Burton&star=Gary%20Oldman:
- La propiedad
Filterse resuelve enscifi stars. - La propiedad
Pagese resuelve en3. - La matriz
Starsse rellena a partir de parámetros de consulta denominadosstar(Name = "star") y se resuelve enLeVar BurtonyGary Oldman.
Pages/Search.razor:
@page "/search"
<h1>Search Example</h1>
<p>Filter: @Filter</p>
<p>Page: @Page</p>
<p>Assignees:</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; }
}
Use NavigationManager.GetUriWithQueryParameter para agregar, cambiar o quitar uno o varios parámetros de consulta en la dirección URL actual:
@inject NavigationManager NavigationManager
...
NavigationManager.GetUriWithQueryParameter("{NAME}", {VALUE})
Para el ejemplo anterior:
- El marcador de posición
{NAME}especifica el nombre del parámetro de consulta. El marcador de posición{VALUE}especifica el valor como un tipo admitido. Los tipos admitidos se enumeran más adelante en esta sección. - Se devuelve una cadena igual a la dirección URL actual con un único parámetro:
- Se agrega si el nombre del parámetro de consulta no existe en la dirección URL actual.
- Se actualiza al valor proporcionado si el parámetro de consulta existe en la dirección URL actual.
- Se quita si el tipo del valor proporcionado admite un valor NULL y el valor es
null.
- El formato de referencia cultural invariable correcto se aplica al tipo especificado (CultureInfo.InvariantCulture).
- El nombre y el valor del parámetro de consulta se codifican como una dirección URL.
- Todos los valores con el nombre del parámetro de consulta correspondiente se reemplazan si hay varias instancias del tipo.
Llame a NavigationManager.GetUriWithQueryParameters para crear un URI construido a partir de Uri con varios parámetros agregados, actualizados o quitados. En cada valor, el marco usa value?.GetType() para determinar el tipo de tiempo de ejecución para cada parámetro de consulta y selecciona el formato invariable de referencia cultural correcto. El marco genera un error para los tipos no admitidos.
@inject NavigationManager NavigationManager
...
NavigationManager.GetUriWithQueryParameters({PARAMETERS})
El marcador de posición {PARAMETERS} es IReadOnlyDictionary<string, object>.
Pase una cadena de URI a GetUriWithQueryParameters para generar uno nuevo a partir de un URI proporcionado con varios parámetros agregados, actualizados o quitados. En cada valor, el marco usa value?.GetType() para determinar el tipo de tiempo de ejecución para cada parámetro de consulta y selecciona el formato invariable de referencia cultural correcto. El marco genera un error para los tipos no admitidos. Los tipos admitidos se enumeran más adelante en esta sección.
@inject NavigationManager NavigationManager
...
NavigationManager.GetUriWithQueryParameters("{URI}", {PARAMETERS})
- El marcador de posición
{URI}es el URI con o sin una cadena de consulta. - El marcador de posición
{PARAMETERS}esIReadOnlyDictionary<string, object>.
Los tipos admitidos son idénticos a los de las restricciones de ruta:
boolDateTimedecimaldoublefloatGuidintlongstring
Los tipos no admitidos incluyen:
- Variantes que admiten un valor NULL de los tipos anteriores (excepto
string, que no tiene una de esas variantes). - Matrices de los tipos anteriores, con independencia de que admitan un valor NULL o no.
Reemplazo de un valor de parámetro de consulta cuando el parámetro existe
NavigationManager.GetUriWithQueryParameter("full name", "Morena Baccarin")
| Dirección URL actual | Dirección URL generada |
|---|---|
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 |
Anexo de un parámetro de consulta y un valor cuando el parámetro no existe
NavigationManager.GetUriWithQueryParameter("name", "Morena Baccarin")
| Dirección URL actual | Dirección URL generada |
|---|---|
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 |
Eliminación de un parámetro de consulta cuando el valor del parámetro es null
NavigationManager.GetUriWithQueryParameter("full name", (string)null)
| Dirección URL actual | Dirección URL generada |
|---|---|
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/ |
Adición, actualización y eliminación de parámetros de consulta
En el ejemplo siguiente:
namese quita, si está presente.agese agrega con un valor de25(int), si no está presente. Si está presente,agese actualiza a un valor de25.eye colorse agrega o actualiza a un valor degreen.
NavigationManager.GetUriWithQueryParameters(
new Dictionary<string, object>
{
["name"] = null,
["age"] = (int?)25,
["eye color"] = "green"
})
| Dirección URL actual | Dirección URL generada |
|---|---|
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 |
Compatibilidad con valores enumerables
En el ejemplo siguiente:
full namese agrega o actualiza aMorena Baccarin, un valor único.- Los parámetros
pingse agregan o reemplazan por35,16,87y240.
NavigationManager.GetUriWithQueryParameters(
new Dictionary<string, object>
{
["full name"] = "Morena Baccarin",
["ping"] = new int?[] { 35, 16, null, 87, 240 }
})
| Dirección URL actual | Dirección URL generada |
|---|---|
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 |
Navegación con una cadena de consulta agregada o modificada
Para navegar con una cadena de consulta agregada o modificada, pase una dirección URL generada a NavigateTo.
En el ejemplo siguiente se llama a:
GetUriWithQueryParameterpara agregar o reemplazar el parámetro de consultanamecon un valor deMorena Baccarin.- Llama a NavigateTo para desencadenar la navegación a la nueva dirección URL.
NavigationManager.NavigateTo(
NavigationManager.GetUriWithQueryParameter("name", "Morena Baccarin"));
Interacción del usuario con el contenido de <Navigating>
El componente Router puede indicar al usuario que se está produciendo una transición de página.
En la parte superior del componente App (App.razor), agregue una directiva @using para el espacio de nombres Microsoft.AspNetCore.Components.Routing:
@using Microsoft.AspNetCore.Components.Routing
Agregue una etiqueta <Navigating> al componente con el marcado que se va a mostrar durante los eventos de transición de la página. Para obtener más información, vea Navigating (Documentación de API).
En el contenido de elemento del enrutador (<Router>...</Router>) del componente App (App.razor):
<Navigating>
<p>Loading the requested page…</p>
</Navigating>
Para obtener un ejemplo en el que se use la propiedad Navigating, vea Ensamblados de carga diferida en Blazor WebAssembly de ASP.NET Core.
Control de eventos de navegación asincrónicos con OnNavigateAsync
El componente Router admite una característica OnNavigateAsync. El controlador OnNavigateAsync se invoca cuando el usuario:
- Visita una ruta por primera vez desplazándose hasta ella directamente en el explorador.
- Navega a una nueva ruta mediante un vínculo o una invocación de NavigationManager.NavigateTo.
En el componente App (App.razor):
<Router AppAssembly="@typeof(Program).Assembly"
OnNavigateAsync="@OnNavigateAsync">
...
</Router>
@code {
private async Task OnNavigateAsync(NavigationContext args)
{
...
}
}
Para obtener un ejemplo en el que se usa OnNavigateAsync, vea Ensamblados de carga diferida en Blazor WebAssembly de ASP.NET Core.
Al realizar la representación previa del servidor en una aplicación Blazor Server o una aplicación hospedada Blazor WebAssembly, OnNavigateAsync se ejecuta dos veces:
- Una primera vez cuando el componente de punto de conexión solicitado se representa inicialmente de forma estática.
- Una segunda vez cuando el explorador representa el componente de punto de conexión.
Para evitar que el código de desarrollador en OnNavigateAsync se ejecute dos veces, el componente App puede almacenar NavigationContext para su uso en OnAfterRender/OnAfterRenderAsync, donde se puede comprobar firstRender. Para obtener más información, vea Detección de cuándo se está obteniendo una representación previa de la aplicación en el artículo Ciclo de vida de Blazor .
Control de las cancelaciones en OnNavigateAsync
El objeto NavigationContext pasado a la devolución de llamada de OnNavigateAsync contiene un elemento CancellationToken que se establece cuando se produce un nuevo evento de navegación. La devolución de llamada de OnNavigateAsync debe iniciarse cuando se establece este token de cancelación para evitar que continúe la ejecución de la devolución de llamada de OnNavigateAsync en una navegación no actualizada.
Si un usuario navega a un punto de conexión, pero inmediatamente después navega a un nuevo punto de conexión, la aplicación no debe seguir ejecutando la devolución de llamada OnNavigateAsync para el primer punto de conexión.
En el ejemplo de componente App siguiente:
- El token de cancelación se pasa en la llamada a
PostAsJsonAsync, que puede cancelar el POST si el usuario se desplaza fuera del punto de conexión/about. - El token de cancelación se establece durante una operación de captura previa del producto si el usuario se desplaza fuera del punto de conexión
/store.
App.razor:
@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 = [345, 789, 135, 689];
foreach (var productId in productIds)
{
context.CancellationToken.ThrowIfCancellationRequested();
Products.Prefetch(productId);
}
}
}
}
Nota
Cuando no se ejecuta si el token de cancelación de NavigationContext se cancela, puede resultar en un comportamiento imprevisto, como la representación de un componente de una navegación anterior.
componentes NavLink y NavMenu
Use un componente NavLink en lugar de los elementos de hipervínculo HTML (<a>) cuando cree vínculos de navegación. Un componente NavLink se comporta igual que un elemento <a>, salvo que alterna una clase CSS active en función de si su elemento href coincide con la dirección URL actual. La clase active ayuda a un usuario a entender qué página es la página activa entre los vínculos de navegación mostrados. Opcionalmente, asigne un nombre de clase CSS a NavLink.ActiveClass para aplicar una clase CSS personalizada al vínculo representado cuando la ruta actual coincida con href.
Nota
El componente NavMenu (NavMenu.razor) se proporciona en la carpeta Shared de una aplicación generada a partir de las plantillas de proyecto de Blazor.
Hay dos opciones de NavLinkMatch que se pueden asignar al atributo Match del elemento <NavLink>:
- NavLinkMatch.All: el elemento NavLink estará activo cuando coincida con la dirección URL actual completa.
- NavLinkMatch.Prefix (predeterminado): el elemento NavLink estará activo cuando coincida con cualquier prefijo de la dirección URL actual.
En el ejemplo anterior, el valor de href="" del elemento NavLink Home coincide con la dirección URL de inicio y solo recibe la clase CSS active en la dirección URL de la ruta de acceso base predeterminada de la aplicación (por ejemplo, https://localhost:5001/). El segundo elemento NavLink recibe la clase active cuando el usuario visita una dirección URL con un prefijo component (por ejemplo, https://localhost:5001/component y https://localhost:5001/component/another-segment).
Se pasan más atributos del componente NavLink a la etiqueta delimitadora representada. En el siguiente ejemplo, el componente NavLink incluye el atributo target:
<NavLink href="example-page" target="_blank">Example page</NavLink>
Se representa el siguiente marcado HTML:
<a href="example-page" target="_blank">Example page</a>
Advertencia
Debido a la forma en que Blazor representa el contenido secundario, la representación de componentes NavLink dentro de un bucle for requiere una variable de índice local si se usa la variable de bucle incremental en el contenido del componente NavLink (secundario):
@for (int c = 0; c < 10; c++)
{
var current = c;
<li ...>
<NavLink ... href="@c">
<span ...></span> @current
</NavLink>
</li>
}
El uso de una variable de índice en este escenario es un requisito para cualquier componente secundario que use una variable de bucle en su contenido secundario, no solo para el componente NavLink.
También puede usar un bucle foreach con Enumerable.Range:
@foreach(var c in Enumerable.Range(0,10))
{
<li ...>
<NavLink ... href="@c">
<span ...></span> @c
</NavLink>
</li>
}
Integración del enrutamiento de puntos de conexión de ASP.NET Core
Esta sección solo se aplica a las aplicaciones Blazor Server.
Blazor Server se integra en el enrutamiento de puntos de conexión de ASP.NET Core. Una aplicación ASP.NET Core está configurada para aceptar conexiones entrantes de componentes interactivos con MapBlazorHub en Program.cs:
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
La configuración típica consiste en enrutar todas las solicitudes a una página de Razor, que actúa como el host del lado servidor de la aplicación Blazor Server. Convencionalmente, la página del host se suele llamar _Host.cshtmlen la carpeta Pages de la aplicación.
La ruta especificada en el archivo de host se denomina ruta de reserva porque tiene una prioridad baja en la búsqueda de rutas, y se solo se usa cuando no se encuentran coincidencias con otras rutas. Esto permite a la aplicación usar otros controladores y páginas sin interferir con el enrutamiento de componentes en la aplicación Blazor Server.
Para información sobre cómo configurar MapFallbackToPage para el hospedaje de servidores de direcciones URL no raíz, consulte Hospedaje e implementación de ASP.NET Core Blazor.
En este artículo, aprenderá a administrar el enrutamiento de solicitudes y a usar el componente NavLink para crear vínculos de navegación en aplicaciones de Blazor.
Plantillas de ruta
El componente Router habilita el enrutamiento a componentes Razor en una aplicación de Blazor. El componente Router se usa en el componente App de aplicaciones de Blazor.
App.razor:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<p>Sorry, there's nothing at this address.</p>
</NotFound>
</Router>
Cuando se compila un componente Razor (.razor) con una directiva @page, la clase de componente generada recibe un elemento RouteAttribute que especifica la plantilla de ruta del componente.
Cuando se inicia la aplicación, el ensamblado especificado como AppAssembly del enrutador se examina para recopilar información de ruta de los componentes de la aplicación que tienen un elemento RouteAttribute.
En tiempo de ejecución, el componente RouteView:
- Recibe el elemento RouteData de Router junto con los parámetros de ruta.
- Representa el componente especificado con su diseño, incluidos los diseños anidados adicionales.
Opcionalmente, se puede especificar un parámetro DefaultLayout con una clase de diseño para los componentes que no tengan especificado un diseño con la directiva @layout. Las plantillas de proyecto de Blazor del marco especifican el componente MainLayout (Shared/MainLayout.razor) como diseño predeterminado de la aplicación. Para más información sobre los diseños, vea Diseños de ASP.NET Core Blazor.
Los componentes admiten varias plantillas de ruta mediante varias directivas @page. El componente de ejemplo siguiente se carga en las solicitudes de /BlazorRoute y /DifferentBlazorRoute.
Pages/BlazorRoute.razor:
@page "/BlazorRoute"
@page "/DifferentBlazorRoute"
<h1>Blazor routing</h1>
Importante
Para que las direcciones URL se resuelvan correctamente, la aplicación debe incluir una etiqueta <base> en su archivo wwwroot/index.html (Blazor WebAssembly) o en su archivo Pages/_Host.cshtml (Blazor Server) con la ruta de acceso base de la aplicación especificada en el atributo href. Para obtener más información, vea Hospedaje e implementación de ASP.NET Core Blazor.
Router no interactúa con los valores de cadena de consulta. Para trabajar con cadenas de consulta, vea la sección Parámetros de cadena de consulta y de análisis.
Suministro de contenido personalizado cuando no se encuentra contenido
El componente Router permite a la aplicación especificar contenido personalizado si no se encuentra contenido para la ruta solicitada.
En el componente App, establezca el contenido personalizado en la plantilla NotFound del componente Router.
App.razor:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<h1>Sorry</h1>
<p>Sorry, there's nothing at this address.</p> b
</NotFound>
</Router>
Nota
Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, consulte Migración de ASP.NET Core 3.1 a 5.0.
Los elementos arbitrarios se admiten como contenido de las etiquetas <NotFound>, como otros componentes interactivos. Para aplicar un diseño predeterminado al contenido de NotFound, vea Diseños de ASP.NET Core Blazor.
Ruta a componentes desde varios ensamblados
Use el parámetro AdditionalAssemblies para especificar más ensamblados para que el componente Router los tenga en cuenta al buscar componentes enrutables. Se examinan los ensamblados adicionales, además del ensamblado especificado para AppAssembly. En el siguiente ejemplo, Component1 es un componente enrutable definido en una biblioteca de clases de componentes a la que se hace referencia. El siguiente ejemplo de AdditionalAssemblies da como resultado una compatibilidad de enrutamiento con Component1.
App.razor:
<Router
AppAssembly="@typeof(Program).Assembly"
AdditionalAssemblies="new[] { typeof(Component1).Assembly }">
@* ... Router component elements ... *@
</Router>
Nota
Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, consulte Migración de ASP.NET Core 3.1 a 5.0.
Parámetros de ruta
El enrutador usa parámetros de ruta para rellenar los parámetros de componente correspondientes con el mismo nombre. Los nombres de parámetros de ruta no distinguen mayúsculas de minúsculas. En el ejemplo siguiente, el parámetro text asigna el valor del segmento de ruta a la propiedad Text del componente. Cuando se realiza una solicitud de /RouteParameter/amazing, el contenido de la etiqueta <h1> se representa como Blazor is amazing!.
Pages/RouteParameter.razor:
@page "/RouteParameter/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
}
Se admiten parámetros opcionales. En el ejemplo siguiente, el parámetro opcional text asigna el valor del segmento de ruta a la propiedad Text del componente. Si el segmento no está presente, el valor de Text se establece en fantastic.
Pages/RouteParameter.razor:
@page "/RouteParameter/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
protected override void OnInitialized()
{
Text = Text ?? "fantastic";
}
}
Use OnParametersSet, en lugar de OnInitialized{Async}, para permitir la navegación de la aplicación al mismo componente con un valor de parámetro opcional diferente. Según el ejemplo anterior, use OnParametersSet cuando el usuario pueda navegar desde /RouteParameter a /RouteParameter/amazing, o desde /RouteParameter/amazing a /RouteParameter:
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
Nota
Los parámetros de ruta no funcionan con los valores de cadena de consulta. Para trabajar con cadenas de consulta, vea la sección Parámetros de cadena de consulta y de análisis.
Restricciones de ruta
Una restricción de ruta fuerza la coincidencia de tipos en un segmento de ruta a un componente.
En el siguiente ejemplo, la ruta al componente User solo coincide en estos casos:
- Existe un segmento de ruta
Iden la dirección URL de la solicitud. - El segmento
Ides un tipo de entero (int).
Pages/User.razor:
@page "/user/{Id:int}"
<h1>User Id: @Id</h1>
@code {
[Parameter]
public int Id { get; set; }
}
Nota
Las restricciones de ruta no funcionan con los valores de cadena de consulta. Para trabajar con cadenas de consulta, vea la sección Parámetros de cadena de consulta y de análisis.
En la siguiente tabla figuran las restricciones de ruta que hay disponibles. Para más información sobre las restricciones de ruta que coinciden con la referencia cultural invariable, consulte la advertencia que aparece después de la tabla.
| Restricción | Ejemplo | Coincidencias de ejemplo | Invariable referencia cultural coincidencia |
|---|---|---|---|
bool |
{active:bool} |
true, FALSE |
No |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Sí |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Sí |
double |
{weight:double} |
1.234, -1,001.01e8 |
Sí |
float |
{weight:float} |
1.234, -1,001.01e8 |
Sí |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} |
No |
int |
{id:int} |
123456789, -123456789 |
Sí |
long |
{ticks:long} |
123456789, -123456789 |
Sí |
Advertencia
Las restricciones de ruta que comprueban la dirección URL y que se convierten en un tipo CLR (como int o DateTime) usan siempre la referencia cultural invariable. Estas restricciones dan por supuesto que la dirección URL no es localizable.
Las restricciones de ruta también funcionan con parámetros opcionales. En el ejemplo siguiente, Id es obligatorio, pero Option es un parámetro de ruta booleano opcional.
Pages/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; }
}
Enrutamiento con direcciones URL que contienen puntos
En el caso de las aplicaciones hospedadas de Blazor WebAssembly y Blazor Server, la plantilla de ruta predeterminada del lado servidor presupone que, si el último segmento de una dirección URL de solicitud contiene un punto (.), se solicita un archivo. Por ejemplo, el enrutador interpreta la dirección URL https://localhost.com:5001/example/some.thing como una solicitud de un archivo denominado some.thing. Sin configuración adicional, una aplicación devuelve una respuesta 404: no encontrado si se pretendía enrutar some.thing a un componente con una directiva @page y some.thing es un valor de parámetro de ruta. Para usar una ruta con uno o más parámetros que contengan un punto, la aplicación debe configurar la ruta con una plantilla personalizada.
Tenga en cuenta el siguiente componente Example que puede recibir un parámetro de ruta del último segmento de la dirección URL.
Pages/Example.razor:
@page "/example/{param?}"
<p>
Param: @Param
</p>
@code {
[Parameter]
public string Param { get; set; }
}
Para permitir que la aplicación Server de una solución de Blazor WebAssembly hospedada enrute la solicitud con un punto en el parámetro param, agregue una plantilla de ruta de archivo de reserva con el parámetro opcional en Startup.Configure.
Startup.cs:
endpoints.MapFallbackToFile("/example/{param?}", "index.html");
Para configurar una aplicación Blazor Server para enrutar la solicitud con un punto en el parámetro de ruta param, agregue una plantilla de ruta de página de reserva con el parámetro opcional en Startup.Configure.
Startup.cs:
endpoints.MapFallbackToPage("/example/{param?}", "/_Host");
Para obtener más información, vea Enrutamiento en ASP.NET Core.
Parámetros de ruta de captura general
Los parámetros de ruta de captura general, que capturan rutas de acceso en varios límites de carpeta, se admiten en los componentes.
Los parámetros de ruta de captura general son:
- Con nombre para que coincida con el nombre del segmento de ruta. La nomenclatura no distingue mayúsculas de minúsculas.
- Tipo
string. El marco no proporciona conversión automática. - Al final de la dirección URL.
Pages/CatchAll.razor:
@page "/catch-all/{*pageRoute}"
@code {
[Parameter]
public string PageRoute { get; set; }
}
Para la dirección URL /catch-all/this/is/a/test con una plantilla de ruta de /catch-all/{*pageRoute}, el valor de PageRoute se establece en this/is/a/test.
Las barras diagonales y los segmentos de la ruta de acceso capturada están descodificados. En el caso de una plantilla de ruta de /catch-all/{*pageRoute}, la dirección URL /catch-all/this/is/a%2Ftest%2A produce this/is/a/test*.
Aplicaciones auxiliares de URI y estado de navegación
Use NavigationManager para administrar los URI y la navegación en el código de C#. NavigationManager proporciona el evento y los métodos que se muestran en la siguiente tabla.
| Miembro | Descripción |
|---|---|
| Uri | Obtiene el URI absoluto actual. |
| BaseUri | Obtiene el URI base (con una barra diagonal final) que se puede anteponer a las rutas de acceso de URI relativo para generar un URI absoluto. Normalmente, BaseUri corresponde al atributo href del elemento <base> del documento en wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server). |
| NavigateTo | Navega al URI especificado. Si forceLoad es true:
|
| LocationChanged | Evento que se desencadena cuando la ubicación de navegación ha cambiado. |
| ToAbsoluteUri | Convierte un URI relativo en un URI absoluto. |
| ToBaseRelativePath | Dado un URI base (por ejemplo, un URI previamente devuelto por BaseUri), convierte un URI absoluto en un URI relativo al prefijo de URI base. |
En el caso del evento LocationChanged, LocationChangedEventArgs proporciona la información siguiente sobre los eventos de navegación:
- Location: la dirección URL de la nueva ubicación.
- IsNavigationIntercepted: si es
true, Blazor ha interceptado la navegación del explorador. Sifalse, NavigationManager.NavigateTo hizo que se produjera la navegación.
El siguiente componente:
- Navega al componente
Counterde la aplicación (Pages/Counter.razor) cuando se selecciona el botón con NavigateTo. - Controla el evento de ubicación cambiado mediante la suscripción a NavigationManager.LocationChanged.
El método
HandleLocationChangedse desenlaza cuando el marco llama aDispose. Al desenlazar el método se permite la recolección de elementos no utilizados del componente.La implementación del registrador registra la siguiente información cuando se selecciona el botón:
BlazorSample.Pages.Navigate: Information: URL of new location: https://localhost:5001/counter
Pages/Navigate.razor:
@page "/navigate"
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager NavigationManager
<h1>Navigate in component code example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent()
{
NavigationManager.NavigateTo("counter");
}
protected override void OnInitialized()
{
NavigationManager.LocationChanged += HandleLocationChanged;
}
private void HandleLocationChanged(object sender, LocationChangedEventArgs e)
{
Logger.LogInformation("URL of new location: {Location}", e.Location);
}
public void Dispose()
{
NavigationManager.LocationChanged -= HandleLocationChanged;
}
}
Para obtener más información sobre la eliminación de componentes, vea Ciclo de vida de los componentes de ASP.NET Core Razor.
Parámetros de cadena de consulta y de análisis
La cadena de consulta de una solicitud se obtiene de la propiedad NavigationManager.Uri:
@inject NavigationManager NavigationManager
...
var query = new Uri(NavigationManager.Uri).Query;
Para analizar los parámetros de una cadena de consulta, un enfoque consiste en usar URLSearchParams con la interoperabilidad de JavaScript (JS):
export createQueryString = (string queryString) => new URLSearchParams(queryString);
Para obtener más información sobre el aislamiento de JavaScript con módulos de JavaScript, consulte Llamada a funciones de JavaScript con métodos de .NET en Blazor de ASP.NET Core.
Interacción del usuario con el contenido de <Navigating>
El componente Router puede indicar al usuario que se está produciendo una transición de página.
En la parte superior del componente App (App.razor), agregue una directiva @using para el espacio de nombres Microsoft.AspNetCore.Components.Routing:
@using Microsoft.AspNetCore.Components.Routing
Agregue una etiqueta <Navigating> al componente con el marcado que se va a mostrar durante los eventos de transición de la página. Para obtener más información, vea Navigating (Documentación de API).
En el contenido de elemento del enrutador (<Router>...</Router>) del componente App (App.razor):
<Navigating>
<p>Loading the requested page…</p>
</Navigating>
Para obtener un ejemplo en el que se use la propiedad Navigating, vea Ensamblados de carga diferida en Blazor WebAssembly de ASP.NET Core.
Control de eventos de navegación asincrónicos con OnNavigateAsync
El componente Router admite una característica OnNavigateAsync. El controlador OnNavigateAsync se invoca cuando el usuario:
- Visita una ruta por primera vez desplazándose hasta ella directamente en el explorador.
- Navega a una nueva ruta mediante un vínculo o una invocación de NavigationManager.NavigateTo.
En el componente App (App.razor):
<Router AppAssembly="@typeof(Program).Assembly"
OnNavigateAsync="@OnNavigateAsync">
...
</Router>
@code {
private async Task OnNavigateAsync(NavigationContext args)
{
...
}
}
Nota
Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, consulte Migración de ASP.NET Core 3.1 a 5.0.
Para obtener un ejemplo en el que se usa OnNavigateAsync, vea Ensamblados de carga diferida en Blazor WebAssembly de ASP.NET Core.
Al realizar la representación previa del servidor en una aplicación Blazor Server o una aplicación hospedada Blazor WebAssembly, OnNavigateAsync se ejecuta dos veces:
- Una primera vez cuando el componente de punto de conexión solicitado se representa inicialmente de forma estática.
- Una segunda vez cuando el explorador representa el componente de punto de conexión.
Para evitar que el código de desarrollador en OnNavigateAsync se ejecute dos veces, el componente App puede almacenar NavigationContext para su uso en OnAfterRender/OnAfterRenderAsync, donde se puede comprobar firstRender. Para obtener más información, vea Detección de cuándo se está obteniendo una representación previa de la aplicación en el artículo Ciclo de vida de Blazor .
Control de las cancelaciones en OnNavigateAsync
El objeto NavigationContext pasado a la devolución de llamada de OnNavigateAsync contiene un elemento CancellationToken que se establece cuando se produce un nuevo evento de navegación. La devolución de llamada de OnNavigateAsync debe iniciarse cuando se establece este token de cancelación para evitar que continúe la ejecución de la devolución de llamada de OnNavigateAsync en una navegación no actualizada.
Si un usuario navega a un punto de conexión, pero inmediatamente después navega a un nuevo punto de conexión, la aplicación no debe seguir ejecutando la devolución de llamada OnNavigateAsync para el primer punto de conexión.
En el ejemplo de componente App siguiente:
- El token de cancelación se pasa en la llamada a
PostAsJsonAsync, que puede cancelar el POST si el usuario se desplaza fuera del punto de conexión/about. - El token de cancelación se establece durante una operación de captura previa del producto si el usuario se desplaza fuera del punto de conexión
/store.
App.razor:
@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 = [345, 789, 135, 689];
foreach (var productId in productIds)
{
context.CancellationToken.ThrowIfCancellationRequested();
Products.Prefetch(productId);
}
}
}
}
Nota
Con la publicación de ASP.NET Core 5.0.1 y para las versiones 5.x adicionales, el componente Router incluye el parámetro PreferExactMatches establecido en @true. Para más información, consulte Migración de ASP.NET Core 3.1 a 5.0.
Nota
Cuando no se ejecuta si el token de cancelación de NavigationContext se cancela, puede resultar en un comportamiento imprevisto, como la representación de un componente de una navegación anterior.
componentes NavLink y NavMenu
Use un componente NavLink en lugar de los elementos de hipervínculo HTML (<a>) cuando cree vínculos de navegación. Un componente NavLink se comporta igual que un elemento <a>, salvo que alterna una clase CSS active en función de si su elemento href coincide con la dirección URL actual. La clase active ayuda a un usuario a entender qué página es la página activa entre los vínculos de navegación mostrados. Opcionalmente, asigne un nombre de clase CSS a NavLink.ActiveClass para aplicar una clase CSS personalizada al vínculo representado cuando la ruta actual coincida con href.
Nota
El componente NavMenu (NavMenu.razor) se proporciona en la carpeta Shared de una aplicación generada a partir de las plantillas de proyecto de Blazor.
Hay dos opciones de NavLinkMatch que se pueden asignar al atributo Match del elemento <NavLink>:
- NavLinkMatch.All: el elemento NavLink estará activo cuando coincida con la dirección URL actual completa.
- NavLinkMatch.Prefix (predeterminado): el elemento NavLink estará activo cuando coincida con cualquier prefijo de la dirección URL actual.
En el ejemplo anterior, el valor de href="" del elemento NavLink Home coincide con la dirección URL de inicio y solo recibe la clase CSS active en la dirección URL de la ruta de acceso base predeterminada de la aplicación (por ejemplo, https://localhost:5001/). El segundo elemento NavLink recibe la clase active cuando el usuario visita una dirección URL con un prefijo component (por ejemplo, https://localhost:5001/component y https://localhost:5001/component/another-segment).
Se pasan más atributos del componente NavLink a la etiqueta delimitadora representada. En el siguiente ejemplo, el componente NavLink incluye el atributo target:
<NavLink href="example-page" target="_blank">Example page</NavLink>
Se representa el siguiente marcado HTML:
<a href="example-page" target="_blank">Example page</a>
Advertencia
Debido a la forma en que Blazor representa el contenido secundario, la representación de componentes NavLink dentro de un bucle for requiere una variable de índice local si se usa la variable de bucle incremental en el contenido del componente NavLink (secundario):
@for (int c = 0; c < 10; c++)
{
var current = c;
<li ...>
<NavLink ... href="@c">
<span ...></span> @current
</NavLink>
</li>
}
El uso de una variable de índice en este escenario es un requisito para cualquier componente secundario que use una variable de bucle en su contenido secundario, no solo para el componente NavLink.
También puede usar un bucle foreach con Enumerable.Range:
@foreach(var c in Enumerable.Range(0,10))
{
<li ...>
<NavLink ... href="@c">
<span ...></span> @c
</NavLink>
</li>
}
Integración del enrutamiento de puntos de conexión de ASP.NET Core
Esta sección solo se aplica a las aplicaciones Blazor Server.
Blazor Server se integra en el enrutamiento de puntos de conexión de ASP.NET Core. Una aplicación ASP.NET Core está configurada para aceptar conexiones entrantes de componentes interactivos con MapBlazorHub en Startup.Configure.
Startup.cs:
using Microsoft.AspNetCore.Builder;
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
La configuración típica consiste en enrutar todas las solicitudes a una página de Razor, que actúa como el host del lado servidor de la aplicación Blazor Server. Convencionalmente, la página del host se suele llamar _Host.cshtmlen la carpeta Pages de la aplicación.
La ruta especificada en el archivo de host se denomina ruta de reserva porque tiene una prioridad baja en la búsqueda de rutas, y se solo se usa cuando no se encuentran coincidencias con otras rutas. Esto permite a la aplicación usar otros controladores y páginas sin interferir con el enrutamiento de componentes en la aplicación Blazor Server.
Para información sobre cómo configurar MapFallbackToPage para el hospedaje de servidores de direcciones URL no raíz, consulte Hospedaje e implementación de ASP.NET Core Blazor.
En este artículo, aprenderá a administrar el enrutamiento de solicitudes y a usar el componente NavLink para crear vínculos de navegación en aplicaciones de Blazor.
Plantillas de ruta
El componente Router habilita el enrutamiento a componentes Razor en una aplicación de Blazor. El componente Router se usa en el componente App de aplicaciones de Blazor.
App.razor:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<p>Sorry, there's nothing at this address.</p>
</NotFound>
</Router>
Cuando se compila un componente Razor (.razor) con una directiva @page, la clase de componente generada recibe un elemento RouteAttribute que especifica la plantilla de ruta del componente.
Cuando se inicia la aplicación, el ensamblado especificado como AppAssembly del enrutador se examina para recopilar información de ruta de los componentes de la aplicación que tienen un elemento RouteAttribute.
En tiempo de ejecución, el componente RouteView:
- Recibe el elemento RouteData de Router junto con los parámetros de ruta.
- Representa el componente especificado con su diseño, incluidos los diseños anidados adicionales.
Opcionalmente, se puede especificar un parámetro DefaultLayout con una clase de diseño para los componentes que no tengan especificado un diseño con la directiva @layout. Las plantillas de proyecto de Blazor del marco especifican el componente MainLayout (Shared/MainLayout.razor) como diseño predeterminado de la aplicación. Para más información sobre los diseños, vea Diseños de ASP.NET Core Blazor.
Los componentes admiten varias plantillas de ruta mediante varias directivas @page. El componente de ejemplo siguiente se carga en las solicitudes de /BlazorRoute y /DifferentBlazorRoute.
Pages/BlazorRoute.razor:
@page "/BlazorRoute"
@page "/DifferentBlazorRoute"
<h1>Blazor routing</h1>
Importante
Para que las direcciones URL se resuelvan correctamente, la aplicación debe incluir una etiqueta <base> en su archivo wwwroot/index.html (Blazor WebAssembly) o en su archivo Pages/_Host.cshtml (Blazor Server) con la ruta de acceso base de la aplicación especificada en el atributo href. Para obtener más información, vea Hospedaje e implementación de ASP.NET Core Blazor.
Router no interactúa con los valores de cadena de consulta. Para trabajar con cadenas de consulta, vea la sección Parámetros de cadena de consulta y de análisis.
Suministro de contenido personalizado cuando no se encuentra contenido
El componente Router permite a la aplicación especificar contenido personalizado si no se encuentra contenido para la ruta solicitada.
En el componente App, establezca el contenido personalizado en la plantilla NotFound del componente Router.
App.razor:
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<h1>Sorry</h1>
<p>Sorry, there's nothing at this address.</p> b
</NotFound>
</Router>
Los elementos arbitrarios se admiten como contenido de las etiquetas <NotFound>, como otros componentes interactivos. Para aplicar un diseño predeterminado al contenido de NotFound, vea Diseños de ASP.NET Core Blazor.
Ruta a componentes desde varios ensamblados
Use el parámetro AdditionalAssemblies para especificar más ensamblados para que el componente Router los tenga en cuenta al buscar componentes enrutables. Se examinan los ensamblados adicionales, además del ensamblado especificado para AppAssembly. En el siguiente ejemplo, Component1 es un componente enrutable definido en una biblioteca de clases de componentes a la que se hace referencia. El siguiente ejemplo de AdditionalAssemblies da como resultado una compatibilidad de enrutamiento con Component1.
App.razor:
<Router
AppAssembly="@typeof(Program).Assembly"
AdditionalAssemblies="new[] { typeof(Component1).Assembly }">
@* ... Router component elements ... *@
</Router>
Parámetros de ruta
El enrutador usa parámetros de ruta para rellenar los parámetros de componente correspondientes con el mismo nombre. Los nombres de parámetros de ruta no distinguen mayúsculas de minúsculas. En el ejemplo siguiente, el parámetro text asigna el valor del segmento de ruta a la propiedad Text del componente. Cuando se realiza una solicitud de /RouteParameter/amazing, el contenido de la etiqueta <h1> se representa como Blazor is amazing!.
Pages/RouteParameter.razor:
@page "/RouteParameter/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
}
No se admiten parámetros opcionales. En el ejemplo siguiente, se aplican dos directivas @page. La primera directiva permite navegar al componente sin un parámetro, mientras que la segunda directiva asigna el valor del parámetro de ruta {text} a la propiedad Text del componente.
Pages/RouteParameter.razor:
@page "/RouteParameter"
@page "/RouteParameter/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
protected override void OnInitialized()
{
Text = Text ?? "fantastic";
}
}
Use OnParametersSet, en lugar de OnInitialized{Async}, para permitir la navegación de la aplicación al mismo componente con un valor de parámetro opcional diferente. Según el ejemplo anterior, use OnParametersSet cuando el usuario pueda navegar desde /RouteParameter a /RouteParameter/amazing, o desde /RouteParameter/amazing a /RouteParameter:
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
Nota
Los parámetros de ruta no funcionan con los valores de cadena de consulta. Para trabajar con cadenas de consulta, vea la sección Parámetros de cadena de consulta y de análisis.
Restricciones de ruta
Una restricción de ruta fuerza la coincidencia de tipos en un segmento de ruta a un componente.
En el siguiente ejemplo, la ruta al componente User solo coincide en estos casos:
- Existe un segmento de ruta
Iden la dirección URL de la solicitud. - El segmento
Ides un tipo de entero (int).
Pages/User.razor:
@page "/user/{Id:int}"
<h1>User Id: @Id</h1>
@code {
[Parameter]
public int Id { get; set; }
}
Nota
Las restricciones de ruta no funcionan con los valores de cadena de consulta. Para trabajar con cadenas de consulta, vea la sección Parámetros de cadena de consulta y de análisis.
En la siguiente tabla figuran las restricciones de ruta que hay disponibles. Para más información sobre las restricciones de ruta que coinciden con la referencia cultural invariable, consulte la advertencia que aparece después de la tabla.
| Restricción | Ejemplo | Coincidencias de ejemplo | Invariable referencia cultural coincidencia |
|---|---|---|---|
bool |
{active:bool} |
true, FALSE |
No |
datetime |
{dob:datetime} |
2016-12-31, 2016-12-31 7:32pm |
Sí |
decimal |
{price:decimal} |
49.99, -1,000.01 |
Sí |
double |
{weight:double} |
1.234, -1,001.01e8 |
Sí |
float |
{weight:float} |
1.234, -1,001.01e8 |
Sí |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} |
No |
int |
{id:int} |
123456789, -123456789 |
Sí |
long |
{ticks:long} |
123456789, -123456789 |
Sí |
Advertencia
Las restricciones de ruta que comprueban la dirección URL y que se convierten en un tipo CLR (como int o DateTime) usan siempre la referencia cultural invariable. Estas restricciones dan por supuesto que la dirección URL no es localizable.
Enrutamiento con direcciones URL que contienen puntos
En el caso de las aplicaciones hospedadas de Blazor WebAssembly y Blazor Server, la plantilla de ruta predeterminada del lado servidor presupone que, si el último segmento de una dirección URL de solicitud contiene un punto (.), se solicita un archivo. Por ejemplo, el enrutador interpreta la dirección URL https://localhost.com:5001/example/some.thing como una solicitud de un archivo denominado some.thing. Sin configuración adicional, una aplicación devuelve una respuesta 404: no encontrado si se pretendía enrutar some.thing a un componente con una directiva @page y some.thing es un valor de parámetro de ruta. Para usar una ruta con uno o más parámetros que contengan un punto, la aplicación debe configurar la ruta con una plantilla personalizada.
Tenga en cuenta el siguiente componente Example que puede recibir un parámetro de ruta del último segmento de la dirección URL.
Pages/Example.razor:
@page "/example"
@page "/example/{param}"
<p>
Param: @Param
</p>
@code {
[Parameter]
public string Param { get; set; }
}
Para permitir que la aplicación Server de una solución de Blazor WebAssembly hospedada enrute la solicitud con un punto en el parámetro param, agregue una plantilla de ruta de archivo de reserva con el parámetro opcional en Startup.Configure.
Startup.cs:
endpoints.MapFallbackToFile("/example/{param?}", "index.html");
Para configurar una aplicación Blazor Server para enrutar la solicitud con un punto en el parámetro de ruta param, agregue una plantilla de ruta de página de reserva con el parámetro opcional en Startup.Configure.
Startup.cs:
endpoints.MapFallbackToPage("/example/{param?}", "/_Host");
Para obtener más información, vea Enrutamiento en ASP.NET Core.
Parámetros de ruta de captura general
Los parámetros de ruta de captura general se admiten en ASP.NET Core 5.0 o posterior. Para más información, seleccione la versión 5.0 de este artículo.
Aplicaciones auxiliares de URI y estado de navegación
Use NavigationManager para administrar los URI y la navegación en el código de C#. NavigationManager proporciona el evento y los métodos que se muestran en la siguiente tabla.
| Miembro | Descripción |
|---|---|
| Uri | Obtiene el URI absoluto actual. |
| BaseUri | Obtiene el URI base (con una barra diagonal final) que se puede anteponer a las rutas de acceso de URI relativo para generar un URI absoluto. Normalmente, BaseUri corresponde al atributo href del elemento <base> del documento en wwwroot/index.html (Blazor WebAssembly) o Pages/_Host.cshtml (Blazor Server). |
| NavigateTo | Navega al URI especificado. Si forceLoad es true:
|
| LocationChanged | Evento que se desencadena cuando la ubicación de navegación ha cambiado. |
| ToAbsoluteUri | Convierte un URI relativo en un URI absoluto. |
| ToBaseRelativePath | Dado un URI base (por ejemplo, un URI previamente devuelto por BaseUri), convierte un URI absoluto en un URI relativo al prefijo de URI base. |
En el caso del evento LocationChanged, LocationChangedEventArgs proporciona la información siguiente sobre los eventos de navegación:
- Location: la dirección URL de la nueva ubicación.
- IsNavigationIntercepted: si es
true, Blazor ha interceptado la navegación del explorador. Sifalse, NavigationManager.NavigateTo hizo que se produjera la navegación.
El siguiente componente:
- Navega al componente
Counterde la aplicación (Pages/Counter.razor) cuando se selecciona el botón con NavigateTo. - Controla el evento de ubicación cambiado mediante la suscripción a NavigationManager.LocationChanged.
El método
HandleLocationChangedse desenlaza cuando el marco llama aDispose. Al desenlazar el método se permite la recolección de elementos no utilizados del componente.La implementación del registrador registra la siguiente información cuando se selecciona el botón:
BlazorSample.Pages.Navigate: Information: URL of new location: https://localhost:5001/counter
Pages/Navigate.razor:
@page "/navigate"
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager NavigationManager
<h1>Navigate in component code example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent()
{
NavigationManager.NavigateTo("counter");
}
protected override void OnInitialized()
{
NavigationManager.LocationChanged += HandleLocationChanged;
}
private void HandleLocationChanged(object sender, LocationChangedEventArgs e)
{
Logger.LogInformation("URL of new location: {Location}", e.Location);
}
public void Dispose()
{
NavigationManager.LocationChanged -= HandleLocationChanged;
}
}
Para obtener más información sobre la eliminación de componentes, vea Ciclo de vida de los componentes de ASP.NET Core Razor.
Parámetros de cadena de consulta y de análisis
La cadena de consulta de una solicitud se obtiene de la propiedad NavigationManager.Uri:
@inject NavigationManager NavigationManager
...
var query = new Uri(NavigationManager.Uri).Query;
Para analizar los parámetros de una cadena de consulta, un enfoque consiste en usar URLSearchParams con la interoperabilidad de JavaScript (JS):
componentes NavLink y NavMenu
Use un componente NavLink en lugar de los elementos de hipervínculo HTML (<a>) cuando cree vínculos de navegación. Un componente NavLink se comporta igual que un elemento <a>, salvo que alterna una clase CSS active en función de si su elemento href coincide con la dirección URL actual. La clase active ayuda a un usuario a entender qué página es la página activa entre los vínculos de navegación mostrados. Opcionalmente, asigne un nombre de clase CSS a NavLink.ActiveClass para aplicar una clase CSS personalizada al vínculo representado cuando la ruta actual coincida con href.
Nota
El componente NavMenu (NavMenu.razor) se proporciona en la carpeta Shared de una aplicación generada a partir de las plantillas de proyecto de Blazor.
Hay dos opciones de NavLinkMatch que se pueden asignar al atributo Match del elemento <NavLink>:
- NavLinkMatch.All: el elemento NavLink estará activo cuando coincida con la dirección URL actual completa.
- NavLinkMatch.Prefix (predeterminado): el elemento NavLink estará activo cuando coincida con cualquier prefijo de la dirección URL actual.
En el ejemplo anterior, el valor de href="" del elemento NavLink Home coincide con la dirección URL de inicio y solo recibe la clase CSS active en la dirección URL de la ruta de acceso base predeterminada de la aplicación (por ejemplo, https://localhost:5001/). El segundo elemento NavLink recibe la clase active cuando el usuario visita una dirección URL con un prefijo component (por ejemplo, https://localhost:5001/component y https://localhost:5001/component/another-segment).
Se pasan más atributos del componente NavLink a la etiqueta delimitadora representada. En el siguiente ejemplo, el componente NavLink incluye el atributo target:
<NavLink href="example-page" target="_blank">Example page</NavLink>
Se representa el siguiente marcado HTML:
<a href="example-page" target="_blank">Example page</a>
Advertencia
Debido a la forma en que Blazor representa el contenido secundario, la representación de componentes NavLink dentro de un bucle for requiere una variable de índice local si se usa la variable de bucle incremental en el contenido del componente NavLink (secundario):
@for (int c = 0; c < 10; c++)
{
var current = c;
<li ...>
<NavLink ... href="@c">
<span ...></span> @current
</NavLink>
</li>
}
El uso de una variable de índice en este escenario es un requisito para cualquier componente secundario que use una variable de bucle en su contenido secundario, no solo para el componente NavLink.
También puede usar un bucle foreach con Enumerable.Range:
@foreach(var c in Enumerable.Range(0,10))
{
<li ...>
<NavLink ... href="@c">
<span ...></span> @c
</NavLink>
</li>
}
Integración del enrutamiento de puntos de conexión de ASP.NET Core
Esta sección solo se aplica a las aplicaciones Blazor Server.
Blazor Server se integra en el enrutamiento de puntos de conexión de ASP.NET Core. Una aplicación ASP.NET Core está configurada para aceptar conexiones entrantes de componentes interactivos con MapBlazorHub en Startup.Configure.
Startup.cs:
using Microsoft.AspNetCore.Builder;
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
La configuración típica consiste en enrutar todas las solicitudes a una página de Razor, que actúa como el host del lado servidor de la aplicación Blazor Server. Convencionalmente, la página del host se suele llamar _Host.cshtmlen la carpeta Pages de la aplicación.
La ruta especificada en el archivo de host se denomina ruta de reserva porque tiene una prioridad baja en la búsqueda de rutas, y se solo se usa cuando no se encuentran coincidencias con otras rutas. Esto permite a la aplicación usar otros controladores y páginas sin interferir con el enrutamiento de componentes en la aplicación Blazor Server.
Para información sobre cómo configurar MapFallbackToPage para el hospedaje de servidores de direcciones URL no raíz, consulte Hospedaje e implementación de ASP.NET Core Blazor.