Enrutamiento y navegación de Blazor de ASP.NET Core
Nota
Esta no es la versión más reciente de este artículo. Para la versión actual, consulta la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulta la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulta la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulta la versión .NET 8 de este artículo.
En este artículo se explica cómo administrar el enrutamiento de solicitudes de la aplicación Blazor y a usar el componente NavLink para crear vínculos de navegación.
Importante
En los ejemplos de código de este artículo se muestran los métodos llamados en Navigation
, que es un NavigationManager insertado en clases y componentes.
Enrutamiento estático frente a interactivo
Esta sección es aplicable a Blazor Web App.
Si la representación previa está habilitada, el router Blazor (componente Router
, <Router>
en Routes.razor
) realiza el enrutamiento estático a los componentes durante la representación estática del lado del servidor (SSR estático). Este tipo de enrutamiento se denomina enrutamiento estático.
Cuando se asigna un modo de representación interactivo al componente Routes
, el enrutador Blazor se vuelve interactivo después de SSR estático con enrutamiento estático en el servidor. Este tipo de enrutamiento se denomina enrutamiento interactivo.
Los enrutadores estáticos usan el enrutamiento de puntos de conexión y la ruta de acceso de la solicitud HTTP para determinar qué componente se va a representar. Cuando el enrutador se vuelve interactivo, usa la dirección URL del documento (la dirección URL de la barra de direcciones del explorador) para determinar qué componente se va a representar. Esto significa que el enrutador interactivo puede cambiar dinámicamente qué componente se representa si la dirección URL del documento cambia dinámicamente a otra dirección URL interna válida y puede hacerlo sin realizar una solicitud HTTP para capturar nuevo contenido de página.
El enrutamiento interactivo también impide la representación previa porque no se solicita contenido de página nueva desde el servidor con una solicitud de página normal. Para obtener más información, consulta Representación previa de componentes Razor de ASP.NET Core .
Plantillas de ruta
El componente Router permite el enrutamiento a los componentes Razor y se encuentra en el componente Routes
de la aplicación (Components/Routes.razor
).
El componente Router habilita el enrutamiento a los componentes Razor. El componente Router se usa en el componente App
(App.razor
).
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
(MainLayout.razor
) como diseño predeterminado de la aplicación. Para obtener más información sobre los diseños, consulta Diseños de Blazor en ASP.NET Core.
Los componentes admiten varias plantillas de ruta mediante varias directivas @page
. El componente de ejemplo siguiente se carga en las solicitudes de /blazor-route
y /different-blazor-route
.
BlazorRoute.razor
:
@page "/blazor-route"
@page "/different-blazor-route"
<PageTitle>Routing</PageTitle>
<h1>Routing Example</h1>
<p>
This page is reached at either <code>/blazor-route</code> or
<code>/different-blazor-route</code>.
</p>
@page "/blazor-route"
@page "/different-blazor-route"
<PageTitle>Routing</PageTitle>
<h1>Routing Example</h1>
<p>
This page is reached at either <code>/blazor-route</code> or
<code>/different-blazor-route</code>.
</p>
@page "/blazor-route"
@page "/different-blazor-route"
<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"
<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"
<h1>Blazor routing</h1>
@page "/blazor-route"
@page "/different-blazor-route"
<h1>Blazor routing</h1>
Importante
Para que las direcciones URL se resuelvan correctamente, la aplicación debe incluir una etiqueta <base>
(ubicación del contenido de <head>
) con la ruta de acceso base de la aplicación especificada en el atributo href
. Para obtener más información, consulta 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, consulta la sección Cadena de consulta.
Como alternativa a especificar la plantilla de ruta como literal de cadena con la directiva @page
, se pueden especificar plantillas de ruta basadas en constantes con la directiva @attribute
.
En el ejemplo siguiente, la directiva @page
de un componente se reemplaza por la directiva @attribute
y la plantilla de ruta basada en constantes en Constants.CounterRoute
, que se establece en otra parte de la aplicación en "/counter
”:
- @page "/counter"
+ @attribute [Route(Constants.CounterRoute)]
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, vea Migración de ASP.NET Core 3.1 a 5.0.
Foco en un elemento de la navegación
El componente FocusOnNavigate establece 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.
<FocusOnNavigate RouteData="routeData" Selector="h1" />
Cuando el componente Router 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 anuncia una navegación 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.
Establezca contenido personalizado para el parámetro Router del componente NotFound:
<Router ...>
...
<NotFound>
...
</NotFound>
</Router>
Los elementos arbitrarios se admiten como contenido de los parámetros NotFound, como otros componentes interactivos. Para aplicar un diseño predeterminado al contenido de NotFound, vea Diseños de Blazor en ASP.NET Core.
Importante
Los objetos Blazor Web App no usan el parámetro NotFound (marcado <NotFound>...</NotFound>
), pero el parámetro es compatible con versiones anteriores para evitar un cambio importante en el marco. La canalización de middleware del lado servidor ASP.NET procesa las solicitudes en el servidor. Usa técnicas del lado servidor para controlar las solicitudes incorrectas. Para obtener más información, vea Modos de representación de ASP.NET CoreBlazor.
Ruta a componentes desde varios ensamblados
Esta sección es aplicable a Blazor Web App.
Use el parámetro AdditionalAssemblies del componente Router y el constructor de convenciones de punto de conexión AddAdditionalAssemblies para descubrir componentes enrutables en ensamblados adicionales. Las siguientes subsecciones explican cuándo y cómo usar cada API.
Enrutamiento estático
Para detectar componentes enrutables de ensamblados adicionales para la representación estática del lado servidor (SSR estático), incluso si el enrutador se convierte más adelante en interactivo para la representación interactiva, los ensamblados deben revelarse al marco Blazor. Llame al método AddAdditionalAssemblies con los ensamblados adicionales encadenados a MapRazorComponents en el archivo Program
del proyecto del servidor.
El siguiente ejemplo incluye los componentes enrutables en el ensamblado del proyecto de BlazorSample.Client
usando el archivo _Imports.razor
del proyecto:
app.MapRazorComponents<App>()
.AddAdditionalAssemblies(typeof(BlazorSample.Client._Imports).Assembly);
Nota:
La guía anterior también se aplica en escenarios de biblioteca de clases de componentes. Encontrará orientación adicional importante para las bibliotecas de clases y SSR estático en Bibliotecas de clases de ASP.NET Core Razor (RCL) con representación estática del lado del servidor (SSR estático).
Enrutamiento interactivo
Se puede asignar un modo de enrutador interactivo al componente de Routes
(Routes.razor
) que hace que el enrutador de Blazor se vuelva interactivo tras el SSR estático y el enrutamiento estático en el servidor. Por ejemplo, <Routes @rendermode="InteractiveServer" />
asigna la representación interactiva del lado servidor (SSR interactiva) al componente Routes
. El componente Router
hereda la representación interactiva del lado del servidor (SSR interactiva) del componente Routes
. El enrutador se vuelve interactivo después del enrutamiento estático en el servidor.
La navegación interna para el enrutamiento interactivo no implica solicitar contenido de página nuevo desde el servidor. Por lo tanto, la representación previa no se produce para las solicitudes de página internas. Para más información, consulte Representación previa de componentes Razor de ASP.NET Core .
Si el componente Routes
está definido en el proyecto del servidor, el parámetro AdditionalAssemblies del componente Router
debería incluir el ensamblado del proyecto .Client
. Esto permite que el enrutador funcione correctamente cuando se representa de forma interactiva.
En el siguiente ejemplo, el componente Routes
se encuentra en el proyecto de servidor, y el archivo _Imports.razor
del proyecto BlazorSample.Client
indica el ensamblado para buscar componentes enrutables:
<Router
AppAssembly="..."
AdditionalAssemblies="new[] { typeof(BlazorSample.Client._Imports).Assembly }">
...
</Router>
Se examinan los ensamblados adicionales, además del ensamblado especificado para AppAssembly.
Nota:
La guía anterior también se aplica en escenarios de biblioteca de clases de componentes.
Como alternativa, los componentes enrutables solo existen en el proyecto .Client
con WebAssembly interactivo global o representación automática aplicada, y el componente Routes
se define en el proyecto .Client
, no en el proyecto servidor. En este caso, no hay ensamblados externos con componentes enrutables, por lo que no es necesario especificar un valor para AdditionalAssemblies.
Esta sección es aplicable a aplicaciones Blazor Server.
Use el parámetro AdditionalAssemblies del componente Router y el constructor de convenciones de punto de conexión AddAdditionalAssemblies para descubrir componentes enrutables en ensamblados adicionales.
En el siguiente ejemplo, Component1
es un componente enrutable definido en una biblioteca de clases de componentes llamada ComponentLibrary
:
<Router
AppAssembly="..."
AdditionalAssemblies="new[] { typeof(ComponentLibrary.Component1).Assembly }">
...
</Router>
Se examinan los ensamblados adicionales, además del ensamblado especificado para AppAssembly.
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 para /route-parameter-1/amazing
, el contenido se representa como Blazor is amazing!
.
RouteParameter1.razor
:
@page "/route-parameter-1/{text}"
<PageTitle>Route Parameter 1</PageTitle>
<h1>Route Parameter Example 1</h1>
<p>Blazor is @Text!</p>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<PageTitle>Route Parameter 1</PageTitle>
<h1>Route Parameter Example 1</h1>
<p>Blazor is @Text!</p>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
}
@page "/route-parameter-1/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
}
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
.
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.
RouteParameter2.razor
:
@page "/route-parameter-2/{text?}"
<PageTitle>Route Parameter 2</PageTitle>
<h1>Route Parameter Example 2</h1>
<p>Blazor is @Text!</p>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnParametersSet() => Text = Text ?? "fantastic";
}
@page "/route-parameter-2/{text?}"
<PageTitle>Route Parameter 2</PageTitle>
<h1>Route Parameter Example 2</h1>
<p>Blazor is @Text!</p>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnParametersSet() => Text = Text ?? "fantastic";
}
@page "/route-parameter-2/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
}
@page "/route-parameter-2/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
}
@page "/route-parameter-2/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
}
@page "/route-parameter-2"
@page "/route-parameter-2/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string Text { get; set; }
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
}
Cuando se usa el método del ciclo de vida OnInitialized{Async}
en lugar del método del ciclo de vida OnParametersSet{Async}
, la asignación predeterminada de la propiedad Text
a fantastic
no se produce si el usuario navega dentro del mismo componente. Por ejemplo, esta situación surge cuando el usuario navega de /route-parameter-2/amazing
a /route-parameter-2
. A medida que la instancia del componente persiste y acepta nuevos parámetros, el método OnInitialized
no se invoca de nuevo.
Nota:
Los parámetros de ruta no funcionan con los valores de cadena de consulta. Para trabajar con cadenas de consulta, consulta la sección Cadena de consulta.
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
Id
en la dirección URL de la solicitud. - El segmento
Id
es un tipo de entero (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; }
}
Nota:
Las restricciones de ruta no funcionan con los valores de cadena de consulta. Para trabajar con cadenas de consulta, consulta la sección Cadena de consulta.
En la siguiente tabla figuran las restricciones de ruta que hay disponibles. Para obtener más información sobre las restricciones de ruta que coinciden con la referencia cultural invariable, consulta 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} |
00001111-aaaa-2222-bbbb-3333cccc4444 , {00001111-aaaa-2222-bbbb-3333cccc4444} |
No |
int |
{id:int} |
123456789 , -123456789 |
Sí |
long |
{ticks:long} |
123456789 , -123456789 |
Sí |
nonfile |
{parameter:nonfile} |
No BlazorSample.styles.css , no favicon.ico |
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.
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; }
}
Evitar la captura de archivos en un parámetro de ruta
La siguiente plantilla de ruta captura accidentalmente las rutas de acceso de recursos estáticos en su parámetro de ruta opcional (Optional
). Por ejemplo, se captura la hoja de estilos de la aplicación (.styles.css
), que interrumpe los estilos de la aplicación:
@page "/{optional?}"
...
@code {
[Parameter]
public string? Optional { get; set; }
}
Para restringir un parámetro de ruta para capturar rutas de acceso que no son de archivo, usa la restricción :nonfile
en la plantilla de ruta:
@page "/{optional:nonfile?}"
Enrutamiento con direcciones URL que contienen puntos
Una plantilla de ruta predeterminada del lado servidor supone que si el último segmento de una dirección URL de solicitud contiene un punto (.
) es porque se solicita un archivo. Por ejemplo, el enrutador interpreta la dirección URL relativa /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.
Ten en cuenta el siguiente componente Example
que puede recibir un parámetro de ruta del último segmento de la dirección 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; }
}
Para permitir que la aplicación Server de una Blazor WebAssemblysolución hospedada enrute la solicitud con un punto en el parámetro de ruta param
, agrega una plantilla de ruta de archivo de reserva con el parámetro opcional en el archivo Program
:
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
, agrega una plantilla de ruta de página de reserva con el parámetro opcional en el archivo Program
:
app.MapFallbackToPage("/example/{param?}", "/_Host");
Para obtener más información, consulta Enrutamiento en ASP.NET Core.
Para permitir que la aplicación Server de una Blazor WebAssemblysolución hospedada enrute la solicitud con un punto en el parámetro de ruta param
, agrega 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
, agrega 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, consulta 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.
CatchAll.razor
:
@page "/catch-all/{*pageRoute}"
<PageTitle>Catch All</PageTitle>
<h1>Catch All Parameters Example</h1>
<p>Add some URI segments to the route and request the page again.</p>
<p>
PageRoute: @PageRoute
</p>
@code {
[Parameter]
public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"
<PageTitle>Catch All</PageTitle>
<h1>Catch All Parameters Example</h1>
<p>Add some URI segments to the route and request the page again.</p>
<p>
PageRoute: @PageRoute
</p>
@code {
[Parameter]
public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"
@code {
[Parameter]
public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"
@code {
[Parameter]
public string? PageRoute { get; set; }
}
@page "/catch-all/{*pageRoute}"
@code {
[Parameter]
public string PageRoute { get; set; }
}
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
Usa 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 (ubicación del contenido de <head> ). |
NavigateTo | Navega al URI especificado. Si forceLoad es false :
forceLoad es true :
Para más información, consulte la sección Navegación mejorada y control de formularios. Si |
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 | En función del URI base de la aplicación, convierte un URI absoluto en un URI relativo al prefijo de URI base. Para obtener un ejemplo, consulte la sección Generar un URI relativo al prefijo de URI base. |
RegisterLocationChangingHandler |
Registra un controlador para procesar los eventos de navegación entrantes. La llamada a NavigateTo siempre invoca al controlador. |
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, consulta la sección Cadenas consulta. |
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 (ubicación del contenido de <head> ). |
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 | En función del URI base de la aplicación, convierte un URI absoluto en un URI relativo al prefijo de URI base. Para obtener un ejemplo, consulte la sección Generar un URI relativo al prefijo de URI base. |
RegisterLocationChangingHandler |
Registra un controlador para procesar los eventos de navegación entrantes. La llamada a NavigateTo siempre invoca al controlador. |
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, consulta la sección Cadenas consulta. |
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 (ubicación del contenido de <head> ). |
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 | En función del URI base de la aplicación, convierte un URI absoluto en un URI relativo al prefijo de URI base. Para obtener un ejemplo, consulta la sección Generar 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, consulta la sección Cadenas consulta. |
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 (ubicación del contenido de <head> ). |
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 | En función del URI base de la aplicación, convierte un URI absoluto en un URI relativo al prefijo de URI base. Para obtener un ejemplo, consulta la sección Generar un URI relativo al prefijo de URI base. |
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
Counter
de la aplicación (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
HandleLocationChanged
se 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:{PORT}/counter
Navigate.razor
:
@page "/navigate"
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation
<PageTitle>Navigate</PageTitle>
<h1>Navigate Example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent() => Navigation.NavigateTo("counter");
protected override void OnInitialized() =>
Navigation.LocationChanged += HandleLocationChanged;
private void HandleLocationChanged(object? sender, LocationChangedEventArgs e) =>
Logger.LogInformation("URL of new location: {Location}", e.Location);
public void Dispose() => Navigation.LocationChanged -= HandleLocationChanged;
}
@page "/navigate"
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation
<PageTitle>Navigate</PageTitle>
<h1>Navigate Example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent() => Navigation.NavigateTo("counter");
protected override void OnInitialized() =>
Navigation.LocationChanged += HandleLocationChanged;
private void HandleLocationChanged(object? sender, LocationChangedEventArgs e) =>
Logger.LogInformation("URL of new location: {Location}", e.Location);
public void Dispose() => Navigation.LocationChanged -= HandleLocationChanged;
}
@page "/navigate"
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation
<h1>Navigate in component code example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent()
{
Navigation.NavigateTo("counter");
}
protected override void OnInitialized()
{
Navigation.LocationChanged += HandleLocationChanged;
}
private void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
{
Logger.LogInformation("URL of new location: {Location}", e.Location);
}
public void Dispose()
{
Navigation.LocationChanged -= HandleLocationChanged;
}
}
@page "/navigate"
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation
<h1>Navigate in component code example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent()
{
Navigation.NavigateTo("counter");
}
protected override void OnInitialized()
{
Navigation.LocationChanged += HandleLocationChanged;
}
private void HandleLocationChanged(object? sender, LocationChangedEventArgs e)
{
Logger.LogInformation("URL of new location: {Location}", e.Location);
}
public void Dispose()
{
Navigation.LocationChanged -= HandleLocationChanged;
}
}
@page "/navigate"
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation
<h1>Navigate in component code example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent()
{
Navigation.NavigateTo("counter");
}
protected override void OnInitialized()
{
Navigation.LocationChanged += HandleLocationChanged;
}
private void HandleLocationChanged(object sender, LocationChangedEventArgs e)
{
Logger.LogInformation("URL of new location: {Location}", e.Location);
}
public void Dispose()
{
Navigation.LocationChanged -= HandleLocationChanged;
}
}
@page "/navigate"
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<Navigate> Logger
@inject NavigationManager Navigation
<h1>Navigate in component code example</h1>
<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
Navigate to the Counter component
</button>
@code {
private void NavigateToCounterComponent()
{
Navigation.NavigateTo("counter");
}
protected override void OnInitialized()
{
Navigation.LocationChanged += HandleLocationChanged;
}
private void HandleLocationChanged(object sender, LocationChangedEventArgs e)
{
Logger.LogInformation("URL of new location: {Location}", e.Location);
}
public void Dispose()
{
Navigation.LocationChanged -= HandleLocationChanged;
}
}
Para obtener más información sobre la eliminación de componentes, consulta Ciclo de vida de componentes Razor de ASP.NET Core.
Navegación mejorada y control de formularios
Esta sección es aplicable a Blazor Web App.
Las Blazor Web App permiten dos tipos de enrutamiento para la navegación de páginas y las solicitudes de control de formularios:
- Navegación normal (navegación entre documentos): se desencadena la recarga de una página completa para la dirección URL de la solicitud.
- Navegación mejorada (navegación en el mismo documento): Blazor intercepta la solicitud y realiza una solicitud
fetch
en su lugar. Luego, Blazor aplica una revisión al contenido de respuesta en el DOM de la página. La navegación mejorada y el control de formularios de Blazor evitan la necesidad de que se recarguen las páginas completas y conserva más el estado de las páginas, por lo que las páginas se cargan más rápidamente y normalmente sin perder la posición de desplazamiento del usuario en la página.
La navegación mejorada está disponible cuando:
- Se usa el script de Blazor Web App (
blazor.web.js
), no el script de Blazor Server (blazor.server.js
) ni el script de Blazor WebAssembly (blazor.webassembly.js
). - La característica no se deshabilita explícitamente.
- La dirección URL de destino se encuentra dentro del espacio del identificador URI base interno (la ruta de acceso base de la aplicación).
Si están habilitados el enrutamiento del lado servidor y la navegación mejorada están habilitados, los controladores de cambio de ubicación solo se invocan para la navegaciones mediante programación iniciada desde un entorno de ejecución interactivo. En futuras versiones, otros tipos de navegación, como seguir un vínculo, también podrán invocar controladores de cambio de ubicación.
Cuando se produce una navegación mejorada, normalmente se invocan los LocationChanged
controladores de eventos registrados con el servidor interactivo y los runtime de WebAssembly. Hay casos en los que es posible que los controladores de cambio de ubicación no intercepten una navegación mejorada. Por ejemplo, el usuario podría cambiar a otra página antes de que un entorno de ejecución interactivo esté disponible. Por lo tanto, es importante que la lógica de la aplicación no dependa de invocar un controlador de cambio de ubicación, ya que no hay ninguna garantía de que el controlador se ejecute.
Al llamar a NavigateTo:
- Si
forceLoad
esfalse
, que es el valor predeterminado:- Además, la navegación mejorada está disponible en la dirección URL actual, se activa la navegación mejorada de Blazor.
- De lo contrario, Blazor realiza una recarga de la página completa para la dirección URL solicitada.
- Si
forceLoad
estrue
: Blazor realiza una recarga de toda la página para la dirección URL solicitada, tanto si la navegación mejorada está disponible como si no lo está.
Para actualizar la página actual, llama a NavigationManager.Refresh(bool forceLoad = false)
, que siempre realiza una navegación mejorada, en caso de que esté disponible. Si la navegación mejorada no está disponible, Blazor realiza una recarga de toda la página.
Navigation.Refresh();
Pasa true
al parámetro forceLoad
para asegurarte de que siempre se realiza la recarga de una página completa, ni siquiera si la navegación mejorada está disponible:
Navigation.Refresh(true);
La navegación mejorada está activada por defecto, pero puede controlarse jerárquicamente y por enlace mediante el data-enhance-nav
atributo HTML.
Los siguientes ejemplos deshabilitan la navegación mejorada:
<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 el destino noBlazor es un punto de conexión, no se aplica la navegación mejorada, y el JavaScript del lado del cliente reintenta como una carga de página completa. Esto asegura que no haya confusión en el marco sobre las páginas externas que no deben ser parcheados en una página existente.
Para habilitar la administración mejorada de formularios, agrega el parámetro Enhance a EditForm los formularios o el atributo data-enhance
a los formularios HTML (<form>
):
<EditForm ... Enhance ...>
...
</EditForm>
<form ... data-enhance ...>
...
</form>
El control mejorado de formularios no es jerárquico y no fluye a formularios secundarios:
No admitido: no se puede establecer la navegación mejorada en el elemento antecesor de un formulario para habilitar la navegación mejorada para el formulario.
<div ... data-enhance ...>
<form ...>
<!-- NOT enhanced -->
</form>
</div>
Los envíos de formularios mejorados solo funcionan con Blazor puntos de conexión. La publicación de un formulario mejorado en un noBlazor punto de conexión produce un error.
Para deshabilitar la navegación mejorada:
- Para un EditForm, elimina el parámetro Enhance del elemento del formulario (o configúralo a
false
:Enhance="false"
). - Para un HTML
<form>
, elimina el atributodata-enhance
del elemento formulario (o configúralo afalse
:data-enhance="false"
).
Blazor navegación mejorada y el control de formularios pueden deshacer cambios dinámicos en el DOM si el contenido actualizado no forma parte de la renderización del servidor. Para conservar el contenido de un elemento, utiliza el atributo data-permanent
.
En el siguiente ejemplo, el contenido del elemento <div>
se actualiza dinámicamente mediante un script cuando se carga la página:
<div data-permanent>
...
</div>
Una vez que Blazor se ha iniciado en el cliente, puedes utilizar el evento enhancedload
para escuchar las actualizaciones de la página mejorada. Esto permite volver a aplicar cambios en el DOM que pueden haber sido deshechos por una actualización de página mejorada.
Blazor.addEventListener('enhancedload', () => console.log('Enhanced update!'));
Para deshabilitar la navegación mejorada y la administración de formularios de forma global, consulta Inicio de ASP.NET Core Blazor.
La navegación mejorada con representación estática del lado del servidor (SSR estática) requiere una atención especial al cargar JavaScript. Para obtener más información, consulta ASP.NET Core Blazor JavaScript con representación estática del lado servidor.
Generar un URI relativo al prefijo de URI base
En función del URI base de la aplicación, ToBaseRelativePath convierte un URI absoluto en un URI relativo al prefijo de URI base.
Considera el ejemplo siguiente:
try
{
baseRelativePath = Navigation.ToBaseRelativePath(inputURI);
}
catch (ArgumentException ex)
{
...
}
Si el URI base de la aplicación es https://localhost:8000
, se obtienen los siguientes resultados:
- Pasar resultados de
https://localhost:8000/segment
eninputURI
en unbaseRelativePath
desegment
. - Pasar resultados de
https://localhost:8000/segment1/segment2
eninputURI
en unbaseRelativePath
desegment1/segment2
.
Si el URI base de la aplicación no coincide con el URI base de inputURI
, se produce un ArgumentException.
Pasar los resultados de https://localhost:8001/segment
en inputURI
en la siguiente excepción:
System.ArgumentException: 'The URI 'https://localhost:8001/segment' is not contained by the base URI 'https://localhost:8000/'.'
Estado del historial de navegación
NavigationManager usa laHistory API del explorador para mantener el estado del historial de navegación asociado a cada cambio de ubicación realizado por la aplicación. Mantener el estado del historial es especialmente útil en escenarios de redirección externa como, por ejemplo, al autenticar usuarios con proveedores de identity externos. Para obtener información adicional, consulta la sección Opciones de navegación.
Opciones de navegación
Pasa NavigationOptions a NavigateTo para controlar los siguientes comportamientos:
- ForceLoad: puentear el enrutamiento de lado del cliente y forzar al navegador a que cargue la nueva página del servidor, tanto si el enrutador de lado del cliente controla el URI como si no. El valor predeterminado es
false
. - ReplaceHistoryEntry: reemplazar la entrada actual en la pila del historial. Si
false
, se anexa la nueva entrada a la pila del historial. El valor predeterminado esfalse
. - HistoryEntryState: obtiene o establece el estado que se va a anexar a la entrada del historial.
Navigation.NavigateTo("/path", new NavigationOptions
{
HistoryEntryState = "Navigation state"
});
Para obtener información adicional sobre cómo obtener el estado asociado a la entrada del historial de destino en el manejo de los cambios de ubicación, consulta la sección Controlar o impedir cambios de ubicación.
Cadenas de consulta
Utiliza el atributo [SupplyParameterFromQuery]
para especificar que un parámetro del componente procede de la cadena de consulta.
Usa 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
.
Solo los componentes enrutables reciben directamente parámetros de consulta para evitar la subvertir el flujo de información de arriba abajo y dejar claro el orden de procesamiento de los parámetros, tanto por el marco como por la aplicación. Este diseño evita errores sutiles en el código de la aplicación que se escribió suponiendo un orden de procesamiento de parámetros específico. Puedes definir parámetros en cascada personalizados o asignarlos directamente a parámetros de componentes normales para pasar valores de parámetros de consulta a componentes no enrutables.
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.
- 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).
Especifica 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}
:
A diferencia de las propiedades de parámetros de componentes ([Parameter]
), las propiedades [SupplyParameterFromQuery]
se pueden marcar con private
además de con public
.
[SupplyParameterFromQuery(Name = "{QUERY PARAMETER NAME}")]
private string? {COMPONENT PARAMETER NAME} { get; set; }
Al igual que las propiedades de parámetros de componentes ([Parameter]
), las propiedades [SupplyParameterFromQuery]
son siempre propiedades public
en .NET 6/7. En .NET 8 o posterior, las propiedades [SupplyParameterFromQuery]
se pueden marcar con public
o private
.
[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
Filter
se resuelve enscifi stars
. - La propiedad
Page
se resuelve en3
. - La matriz
Stars
se rellena a partir de parámetros de consulta denominadosstar
(Name = "star"
) y se resuelve enLeVar Burton
yGary Oldman
.
Nota
Los parámetros de cadena de consulta del siguiente componente de página enrutable también funcionan en un componente no enrutable sin una @page
directiva (por ejemplo, Search.razor
para un componente compartido Search
usado en otros componentes).
Search.razor
:
@page "/search"
<h1>Search Example</h1>
<p>Filter: @Filter</p>
<p>Page: @Page</p>
@if (Stars is not null)
{
<p>Stars:</p>
<ul>
@foreach (var name in Stars)
{
<li>@name</li>
}
</ul>
}
@code {
[SupplyParameterFromQuery]
private string? Filter { get; set; }
[SupplyParameterFromQuery]
private int? Page { get; set; }
[SupplyParameterFromQuery(Name = "star")]
private string[]? Stars { get; set; }
}
Search.razor
:
@page "/search"
<h1>Search Example</h1>
<p>Filter: @Filter</p>
<p>Page: @Page</p>
@if (Stars is not null)
{
<p>Stars:</p>
<ul>
@foreach (var name in Stars)
{
<li>@name</li>
}
</ul>
}
@code {
[Parameter]
[SupplyParameterFromQuery]
public string? Filter { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public int? Page { get; set; }
[Parameter]
[SupplyParameterFromQuery(Name = "star")]
public string[]? Stars { get; set; }
}
Usa GetUriWithQueryParameter para agregar, cambiar o quitar uno o varios parámetros de consulta en la dirección URL actual:
@inject NavigationManager Navigation
...
Navigation.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.
Llama a 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 Navigation
...
Navigation.GetUriWithQueryParameters({PARAMETERS})
El marcador de posición {PARAMETERS}
es IReadOnlyDictionary<string, object>
.
Pasa 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 Navigation
...
Navigation.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:
bool
DateTime
decimal
double
float
Guid
int
long
string
Los tipos no admitidos incluyen:
- Variantes que admiten un valor NULL de los tipos anteriores.
- Matrices de los tipos anteriores, con independencia de que admitan un valor NULL o no.
Advertencia
Con la compresión, que está habilitada de forma predeterminada, evita crear componentes interactivos del lado servidor (autenticados o autorizados) seguros que representen datos de orígenes que no sean de confianza. Los orígenes que no son de confianza incluyen parámetros de ruta, cadenas de consulta, datos de interoperabilidad JS y cualquier otro origen de datos que un usuario de terceros pueda controlar (bases de datos, servicios externos). Para obtener más información, consulta Guía de ASP.NETBlazorSignalR y Guía de mitigación de amenazas de representación interactiva del lado servidor para ASP.NET Core Blazor.
Reemplazo de un valor de parámetro de consulta cuando el parámetro existe
Navigation.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
Navigation.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
Navigation.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:
name
se quita, si está presente.age
se agrega con un valor de25
(int
), si no está presente. Si está presente,age
se actualiza a un valor de25
.eye color
se agrega o actualiza a un valor degreen
.
Navigation.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 name
se agrega o actualiza aMorena Baccarin
, un valor único.- Los parámetros
ping
se agregan o reemplazan por35
,16
,87
y240
.
Navigation.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, pasa una dirección URL generada a NavigateTo.
En el ejemplo siguiente se llama a:
- GetUriWithQueryParameter para agregar o reemplazar el parámetro de consulta
name
con un valor deMorena Baccarin
. - Llama a NavigateTo para desencadenar la navegación a la nueva dirección URL.
Navigation.NavigateTo(
Navigation.GetUriWithQueryParameter("name", "Morena Baccarin"));
La cadena de consulta de una solicitud se obtiene de la propiedad NavigationManager.Uri:
@inject NavigationManager Navigation
...
var query = new Uri(Navigation.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, consulta Llamada a funciones de JavaScript desde métodos de .NET en Blazor de ASP.NET Core.
Enrutamiento con hash a elementos con nombre
Ve a un elemento con nombre mediante los siguientes enfoques con una referencia hash (#
) al elemento. Las rutas a los elementos dentro del componente y las rutas a los elementos de los componentes externos usan rutas de acceso relativas a la raíz. Una barra diagonal inicial (/
) es opcional.
Los ejemplos de cada uno de los enfoques siguientes muestran la navegación a un elemento con un id
de targetElement
en el componente Counter
:
Elemento delimitador (
<a>
) conhref
:<a href="/counter#targetElement">
Componente NavLink con
href
:<NavLink href="/counter#targetElement">
NavigationManager.NavigateTo pasando la URL relativa:
Navigation.NavigateTo("/counter#targetElement");
En el ejemplo siguiente se muestra el enrutamiento con hash a encabezados H2 con nombre dentro de un componente y a componentes externos.
En los componentes Home
(Home.razor
) y Counter
(Counter.razor
), coloca el marcado siguiente en la parte inferior del marcado de componente existente para que actúe como destinos de navegación. <div>
crea un espacio vertical artificial para demostrar el comportamiento del desplazamiento del explorador:
<div class="border border-info rounded bg-info" style="height:500px"></div>
<h2 id="targetElement">Target H2 heading</h2>
<p>Content!</p>
Agrega el siguiente componente HashedRouting
a la aplicación.
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");
}
}
Interacción del usuario con el contenido de <Navigating>
Si se produce un retraso significativo durante la navegación, por ejemplo durante la carga diferida de ensamblados en una aplicación Blazor WebAssembly o por una conexión de red lenta a una aplicación Blazor del lado del servidor, el componente Router puede indicar al usuario que se está produciendo una transición de página.
En la parte superior del componente que especifica el componente Router, agrega una directiva @using
para el espacio de nombres Microsoft.AspNetCore.Components.Routing:
@using Microsoft.AspNetCore.Components.Routing
Proporciona contenido al parámetro Navigating para que se muestre durante los eventos de transición de página.
En el contenido del elemento enrutador (<Router>...</Router>
):
<Navigating>
<p>Loading the requested page…</p>
</Navigating>
Para obtener un ejemplo en el que se usa la propiedad Navigating, consulta 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.
<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)
{
...
}
}
Para obtener un ejemplo en el que se usa OnNavigateAsync, consulta Ensamblados de carga diferida en Blazor WebAssembly de ASP.NET Core.
Al representar previamente en el servidor, 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 del desarrollador en OnNavigateAsync se ejecute dos veces, el componente Routes
puede almacenar NavigationContext para su uso en el método del ciclo de vida OnAfterRender{Async}
, donde se puede comprobar firstRender
. Para obtener más información, consulta Representación previa con interoperabilidad de JavaScript.
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{Async}
, donde firstRender
se puede comprobar. Para obtener más información, consulta Representación previa con interoperabilidad de JavaScript.
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 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
.
@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);
}
}
}
}
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.
Control o prevención de cambios de ubicación
RegisterLocationChangingHandler registra un controlador para procesar los eventos de navegación entrantes. El contexto del controlador proporcionado porLocationChangingContext incluye las siguientes propiedades:
- TargetLocation: obtiene la ubicación de destino.
- HistoryEntryState: obtiene el estado asociado a la entrada de historial de destino.
- IsNavigationIntercepted: obtiene si la navegación se ha interceptado desde un vínculo.
- CancellationToken: obtiene un CancellationToken para determinar si la navegación se ha cancelado, por ejemplo, para determinar si el usuario ha desencadenado una navegación diferente.
- PreventNavigation: se llama para evitar que la navegación continúe.
Un componente puede registrar varios controladores de cambio de ubicación en el método de ciclo de vida de OnAfterRender{Async}
. La navegación invoca todos los controladores de cambio de ubicación registrados en toda la aplicación (en varios componentes) y cualquier navegación interna los ejecuta en paralelo. Además de NavigateTo, los controladores se invocan:
- Al seleccionar vínculos internos, que son vínculos que apuntan a direcciones URL en la ruta de acceso base de la aplicación.
- Al navegar con los botones hacia delante y atrás en un navegador.
Los controladores solo se ejecutan en la navegación interna dentro de la aplicación. Si el usuario selecciona un vínculo que lleva a un sitio diferente o cambia la barra de direcciones a otro sitio manualmente, los controladores de cambio de ubicación no se ejecutarán.
Implementa IDisposable y elimina los controladores registrados para anular su registro. Para obtener más información, consulta Ciclo de vida de componentes Razor de ASP.NET Core.
Importante
No intentes ejecutar tareas de limpieza a través de la interoperabilidad de JavaScript (JS) al controlar los cambios de ubicación. Usa el patrón MutationObserver
en JS en el cliente. Para obtener más información, consulta Interoperabilidad de JavaScript en Blazor de ASP.NET Core (interoperabilidad de JS).
En el ejemplo siguiente, se registra un controlador de cambio de ubicación en eventos de navegación.
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();
}
Dado que la navegación interna se puede cancelar de forma asincrónica, pueden solaparse varias llamadas a controladores registrados. Por ejemplo, se pueden producir varias llamadas de controlador cuando el usuario selecciona rápidamente el botón Atrás en una página o selecciona varios vínculos antes de ejecutar una navegación. A continuación se muestra un resumen de la lógica de navegación asincrónica:
- Si hubiera algún controlador de cambio de ubicación registrado, se revertiría inicialmente toda la navegación y luego se reproduciría si no se cancela la navegación.
- Si se solapan las solicitudes de navegación, la última solicitud siempre cancelará las solicitudes anteriores, lo que significa lo siguiente:
- La aplicación puede tratar varias selecciones de botón atrás y adelante como una única selección.
- Si el usuario selecciona varios vínculos antes de finalizar la navegación, el último vínculo seleccionado determinará la navegación.
Para obtener información adicional sobre cómo pasar NavigationOptions a NavigateTo para controlar las entradas y el estado de la pila del historial de navegación, consulta la sección Opciones de navegación.
Para obtener código de ejemplo adicional, consulta NavigationManagerComponent
en BasicTestApp
(origen de referencia dotnet/aspnetcore
).
Nota
Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, consulta Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).
El componente NavigationLock
intercepta los eventos de navegación siempre que se represente, "bloqueando" de forma eficaz cualquier navegación determinada hasta que se tome una decisión para continuar o cancelar. Usa NavigationLock
cuando la interceptación de navegación se pueda limitar a la duración de un componente.
Parámetros de NavigationLock:
- ConfirmExternalNavigation establece un diálogo del explorador para pedir al usuario que confirme o cancele la navegación externa. El valor predeterminado es
false
. Mostrar el diálogo de confirmación requiere una interacción inicial del usuario con la página antes de desencadenar la navegación externa con la URL de la barra de direcciones del explorador. Para obtener información adicional sobre el requisito de interacción, consulta Ventana: eventobeforeunload
(documentación de MDN). - OnBeforeInternalNavigation establece una devolución de llamada para eventos de navegación interna.
En el componente NavLock
siguiente:
- El usuario tiene que confirmar un intento de seguir el vínculo al sitio web de Microsoft para que la navegación a
https://www.microsoft.com
se realice correctamente. - PreventNavigation se llama a para evitar que se produzca la navegación si el usuario rechaza confirmar la navegación a través de una llamada de interoperabilidad de JavaScript (JS) que genera el diálogo JS
confirm
.
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();
}
}
}
Para obtener código de ejemplo adicional, consulta el componenteConfigurableNavigationLock
en BasicTestApp
(origen de referencia dotnet/aspnetcore
).
Componente de NavLink
Usa 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, asigna 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
.
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, HomeNavLinkhref=""
coincide con la dirección URL home y solo recibe la clase CSS active
en la ruta de acceso base predeterminada de la aplicación (/
). El segundo elemento NavLink recibe la clase active
cuando el usuario visita una dirección URL con un prefijo component
(por ejemplo, /component
y /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 = 1; c < 4; c++)
{
var ct = c;
<li ...>
<NavLink ...>
<span ...></span> Product #@ct
</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 puedes usar un bucle foreach
con Enumerable.Range:
@foreach (var c in Enumerable.Range(1, 3))
{
<li ...>
<NavLink ...>
<span ...></span> Product #@c
</NavLink>
</li>
}
Las entradas de componente NavLink se pueden crear dinámicamente a partir de los componentes de la aplicación a través de la reflexión. En el siguiente ejemplo se muestra el enfoque general para una mayor personalización.
Para la siguiente demostración, se usa una convención de nomenclatura estándar coherente para los componentes de la aplicación:
- Los nombres de archivo de componentes enrutables usan el Pascal case†, por ejemplo,
Pages/ProductDetail.razor
. - Las rutas de archivos de componentes enrutables hacen coincidir sus direcciones URL en kebab case‡ con guiones que aparecen entre palabras en la plantilla de ruta de un componente. Por ejemplo, se solicita un componente
ProductDetail
con una plantilla de ruta de/product-detail
(@page "/product-detail"
) en un explorador en la dirección URL/product-detail
relativa.
†Pascal Case (letra mayúscula) es una convención de nomenclatura sin espacios y signos de puntuación y con la primera letra de cada palabra en mayúsculas, incluida la primera palabra.
‡Kebab case es una convención de nomenclatura sin espacios y signos de puntuación que usa letras minúsculas y guiones entre palabras.
En el marcado Razor del componente NavMenu
(NavMenu.razor
) en la página Home
predeterminada, se agregan componentes NavLink desde una colección:
<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étodo GetRoutableComponents
del bloque @code
:
public IEnumerable<string> GetRoutableComponents() =>
Assembly.GetExecutingAssembly()
.ExportedTypes
.Where(t => t.IsSubclassOf(typeof(ComponentBase)))
.Where(c => c.GetCustomAttributes(inherit: true)
.OfType<RouteAttribute>()
.Any())
.Where(c => c.Name != "Home" && c.Name != "Error")
.OrderBy(o => o.Name)
.Select(c => c.Name);
En el ejemplo anterior no se incluyen las siguientes páginas en la lista representada de componentes:
- Página
Home
: la página aparece por separado de los vínculos generados automáticamente porque debe aparecer en la parte superior de la lista y establecer el parámetroMatch
. - Página
Error
: la página de error solo se navega por el marco de trabajo y no debe aparecer.
Para obtener un ejemplo del código anterior en una aplicación de ejemplo que puedes ejecutar localmente, obtén la aplicación de muestra Blazor Web App o Blazor WebAssembly.
Integración del enrutamiento de puntos de conexión de ASP.NET Core
Esta sección se aplica a las Blazor Web App que funcionan a través de un circuito.
Esta sección es aplicable a aplicaciones Blazor Server.
Blazor Web App se integra en el enrutamiento de punto de conexión de ASP.NET Core. Una aplicación ASP.NET Core está configurada para aceptar conexiones entrantes de componentes interactivos con MapRazorComponents en el archivo Program
. El componente raíz predeterminado (primer componente cargado) es el App
(App.razor
):
app.MapRazorComponents<App>();
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 el archivo Program
:
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
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
.
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.cshtml
en 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 CoreBlazor.