Partilhar via


ASP.NET Core Blazor roteamento e navegação

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.

Advertência

Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Este artigo explica como gerenciar Blazor roteamento de solicitações de aplicativo e como usar o componente NavLink para criar links de navegação.

Importante

Ao longo deste artigo, os exemplos de código mostram métodos aplicados ao Navigation, que é um NavigationManager injetado nas classes e componentes.

Roteamento estático versus interativo

Esta seção aplica-se a Blazor Web Apps.

Se a pré-renderização estiver ativada, o roteador Blazor (componenteRouter, <Router> no Routes.razor) realiza roteamento estático para os componentes durante a renderização do lado do servidor estática (SSR). Esse tipo de roteamento é chamado roteamento estático.

Quando um modo de renderização interativo é atribuído ao componente Routes, o roteador Blazor torna-se interativo após SSR estático com roteamento estático no servidor. Esse tipo de roteamento é chamado de roteamento interativo .

Os roteadores estáticos usam o roteamento de ponto de extremidade e o caminho de solicitação HTTP para determinar qual componente renderizar. Quando o roteador se torna interativo, ele usa a URL do documento (a URL na barra de endereço do navegador) para determinar qual componente renderizar. Isso significa que o roteador interativo pode alterar dinamicamente qual componente é renderizado se a URL do documento mudar dinamicamente para outra URL interna válida, e pode fazer isso sem executar uma solicitação HTTP para buscar novo conteúdo de página.

O roteamento interativo também impede a pré-renderização porque o novo conteúdo da página não é solicitado ao servidor com uma solicitação de página normal. Para obter mais informações, consulte Persistência de estado pré-renderizado do núcleo ASP.NETBlazor.

Modelos de rotas

O componente Router permite o encaminhamento para componentes Razor e está localizado no componente Routes da aplicação (Components/Routes.razor).

O componente Router permite o roteamento para componentes Razor. O componente Router é usado no componente App (App.razor).

Quando um componente Razor (.razor) com uma diretiva @page é compilado, a classe do componente gerada recebe uma RouteAttribute especificando o modelo de rota do componente.

Quando a aplicação é iniciada, o assembly especificado como AppAssembly do Router é analisado para recolher informações de rota para os componentes da aplicação que têm um RouteAttribute.

Durante a execução, o componente RouteView:

  • Recebe o RouteData do Router juntamente com quaisquer parâmetros de rota.
  • Renderiza o componente especificado com o seu layout , incluindo quaisquer layouts aninhados adicionais.

Opcionalmente, especifique um parâmetro DefaultLayout com uma classe de layout para componentes que não especificam um layout com a diretiva @layout. Os modelos de projeto Blazor do framework especificam o componente MainLayout (MainLayout.razor) como a estrutura padrão da aplicação. Para obter mais informações sobre layouts, consulte layouts do ASP.NET CoreBlazor.

Os componentes suportam vários modelos de rota usando várias diretivas @page. O componente de exemplo a seguir é carregado em solicitações de /blazor-route e /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 as URLs sejam resolvidas corretamente, a aplicação deve incluir uma marca <base> (localização de <head> conteúdo) com o caminho base da aplicação especificado no atributo href. Para obter mais informações, consulte ASP.NET Core caminho base da aplicaçãoBlazor.

O Router não interage com valores de cadeia de caracteres de consulta. Para trabalhar com cadeias de caracteres de consulta, consulte a seção Cadeias de caracteres de consulta.

Como alternativa à especificação do modelo de rota como uma cadeia de caracteres literal com a diretiva @page, modelos de rota baseados em constantes podem ser especificados com a diretiva @attribute.

No exemplo a seguir, a diretiva @page em um componente é substituída pela diretiva @attribute e pelo modelo de rota baseado em constante no Constants.CounterRoute, que é definido em outro lugar do aplicativo como "/counter":

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

Observação

Com o lançamento do .NET 5.0.1 e para quaisquer versões adicionais do 5.x, o Router componente inclui o PreferExactMatches parâmetro definido como @true. Para obter mais informações, consulte Migrar do ASP.NET Core 3.1 para o .NET 5.

Colocar o foco em um elemento na navegação

O componente FocusOnNavigate define o foco da interface do usuário como um elemento baseado em um seletor CSS depois de navegar de uma página para outra.

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

Quando o componente Router navega para uma nova página, o componente FocusOnNavigate define o foco para o cabeçalho de nível superior da página (<h1>). Esta é uma estratégia comum para garantir que uma navegação de página seja anunciada ao usar um leitor de tela.

Fornecer conteúdo personalizado quando o conteúdo não for encontrado

O componente Router permite que o aplicativo especifique conteúdo personalizado se o conteúdo não for encontrado para a rota solicitada.

Defina conteúdo personalizado para o parâmetro Router do componente NotFound:

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

Itens arbitrários são suportados como conteúdo do parâmetro NotFound, como outros componentes interativos. Para aplicar um layout padrão ao NotFound conteúdo, consulte layouts do ASP.NET CoreBlazor.

Blazor Web Apps não usa o parâmetro NotFound (<NotFound>...</NotFound> markup), mas é suportado† para compatibilidade retroativa no .NET 8/9, evitando assim uma alteração disruptiva no framework. O pipeline de middleware ASP.NET Core do lado do servidor processa solicitações no servidor. Use técnicas do lado do servidor para lidar com solicitações incorretas.

suportado neste contexto significa que colocar a marcação <NotFound>...</NotFound> não resulta em excepção, mas usar a marcação também não é eficaz.

Para obter mais informações, consulte os seguintes recursos:

Caminho para componentes de várias montagens

Esta seção aplica-se a Blazor Web Apps.

Use o parâmetro Router do componente AdditionalAssemblies e o construtor de convenções do ponto de extremidade AddAdditionalAssemblies para descobrir componentes enrutáveis em assemblies adicionais. As subseções a seguir explicam quando e como usar cada API.

Roteamento estático

Para descobrir componentes roteáveis a partir de conjuntos adicionais para renderização estática no lado do servidor (SSR estático), mesmo que o roteador posteriormente se torne interativo para renderização interativa, os conjuntos devem ser tornados acessíveis à estrutura Blazor. Chame o método AddAdditionalAssemblies com os assemblies adicionais encadeados a MapRazorComponents no ficheiro Program do projeto de servidor.

O exemplo a seguir inclui os componentes roteáveis no assembly do projeto BlazorSample.Client usando o arquivo _Imports.razor do projeto:

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

Observação

A orientação anterior também se aplica em cenários da biblioteca de classes de componentes . Orientações adicionais importantes para bibliotecas de classes e SSR estático são encontradas em bibliotecas de classes do ASP.NET Core Razor (RCLs) com SSR estático (renderização estática do lado do servidor).

Roteamento interativo

Um modo de renderização interativo pode ser atribuído ao componente Routes (Routes.razor) que faz com que o roteador Blazor se torne interativo após SSR estático e roteamento estático no servidor. Por exemplo, <Routes @rendermode="InteractiveServer" /> atribui renderização interativa do lado do servidor (SSR interativo) ao componente Routes. O componente Router herda a renderização interativa do lado do servidor (SSR interativo) do componente Routes. O roteador torna-se interativo após o roteamento estático no servidor.

A navegação interna para roteamento interativo não envolve a solicitação de novo conteúdo de página do servidor. Portanto, a pré-renderização não ocorre para solicitações de página internas. Para obter mais informações, consulte Persistência de estado pré-renderizado do núcleo ASP.NETBlazor.

Se o componente Routes for definido no projeto de servidor, o parâmetro AdditionalAssemblies do componente Router deverá incluir o assembly do projeto .Client. Isso permite que o roteador funcione corretamente quando processado interativamente.

No exemplo a seguir, o componente Routes está no projeto de servidor e o arquivo de _Imports.razor do projeto BlazorSample.Client indica o assembly para procurar componentes roteáveis:

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

Conjuntos adicionais são analisados além do conjunto especificado para AppAssembly.

Observação

A orientação anterior também se aplica em cenários da biblioteca de classes de componentes .

Como alternativa, os componentes roteáveis só existem no projeto .Client com WebAssembly interativo global ou renderização automática aplicada, e o componente Routes é definido no projeto .Client, não no projeto de servidor. Nesse caso, não há assemblies externos com componentes roteáveis, portanto, não é necessário especificar um valor para AdditionalAssemblies.

Esta secção aplica-se a aplicações Blazor Server.

Use o parâmetro Router do componente AdditionalAssemblies e o construtor de convenções do ponto de extremidade AddAdditionalAssemblies para descobrir componentes enrutáveis em assemblies adicionais.

No exemplo a seguir, Component1 é um componente roteável definido em uma biblioteca de classes de componente referenciada chamada ComponentLibrary:

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

Conjuntos adicionais são analisados além do conjunto especificado para AppAssembly.

Parâmetros de rota

O roteador usa parâmetros de rota para preencher os parâmetros dos componentes correspondentes com o mesmo nome. Os nomes dos parâmetros de rota são insensíveis a maiúsculas e minúsculas. No exemplo a seguir, o parâmetro text atribui o valor do segmento de rota à propriedade Text do componente. Quando uma solicitação é feita para /route-parameter-1/amazing, o conteúdo é processado 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; }
}

Parâmetros opcionais são suportados. No exemplo a seguir, o parâmetro opcional text atribui o valor do segmento de rota à propriedade Text do componente. Se o segmento não estiver presente, o valor de Text será definido como fantastic.

Não há suporte para parâmetros opcionais. No exemplo a seguir, duas diretivas @page são aplicadas. A primeira diretiva permite a navegação para o componente sem um parâmetro. A segunda diretiva atribui o valor do parâmetro de rota {text} à propriedade Text do 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";
    }
}

Quando o método de ciclo de vida OnInitialized{Async} é usado em vez do método de ciclo de vida OnParametersSet{Async}, a atribuição padrão da propriedade Text a fantastic não ocorre se o usuário navegar dentro do mesmo componente. Por exemplo, essa situação surge quando o usuário navega de /route-parameter-2/amazing para /route-parameter-2. Como a instância do componente persiste e aceita novos parâmetros, o método OnInitialized não é invocado novamente.

Observação

Os parâmetros de rota não funcionam com valores de cadeia de caracteres de consulta. Para trabalhar com cadeias de caracteres de consulta, consulte a seção Cadeias de caracteres de consulta.

Restrições de rota

Uma restrição de rota impõe a correspondência de tipos num segmento de rota para um componente.

No exemplo a seguir, a rota para o componente User só corresponde se:

  • Um segmento de rota Id está presente na URL da solicitação.
  • O segmento Id é um tipo inteiro (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; }
}

Observação

As restrições de rota não funcionam com valores de cadeia de caracteres de consulta. Para trabalhar com cadeias de caracteres de consulta, consulte a seção Cadeias de caracteres de consulta.

As restrições de rota mostradas na tabela a seguir estão disponíveis. Para as restrições de rota que correspondem à cultura invariante, consulte o aviso abaixo da tabela para obter mais informações.

Restrição Exemplo Exemplos de combinações Invariante
cultura
emparelhamento
bool {active:bool} true, FALSE Não
datetime {dob:datetime} 2016-12-31, 2016-12-31 7:32pm Sim
decimal {price:decimal} 49.99, -1,000.01 Sim
double {weight:double} 1.234, -1,001.01e8 Sim
float {weight:float} 1.234, -1,001.01e8 Sim
guid {id:guid} 00001111-aaaa-2222-bbbb-3333cccc4444, {00001111-aaaa-2222-bbbb-3333cccc4444} Não
int {id:int} 123456789, -123456789 Sim
long {ticks:long} 123456789, -123456789 Sim
nonfile {parameter:nonfile} Nem BlazorSample.styles.css, nem favicon.ico Sim

Advertência

As restrições de rota que verificam a URL e são convertidas num tipo CLR (como int ou DateTime) utilizam sempre a cultura invariável. Essas restrições pressupõem que a URL não é localizável.

As restrições de rota também funcionam com parâmetros opcionais. No exemplo a seguir, Id é necessário, mas Option é um parâmetro de rota 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; }
}

Evite a captura de arquivos num parâmetro de rota

O modelo de rota a seguir captura inadvertidamente caminhos de ativos estáticos em seu parâmetro de rota opcional (Optional). Por exemplo, a folha de estilo do aplicativo (.styles.css) é capturada, o que quebra os estilos do aplicativo:

@page "/{optional?}"

...

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

Para restringir um parâmetro de rota à captura de caminhos que não sejam de arquivo, use a restrição :nonfile no modelo de rota.

@page "/{optional:nonfile?}"

Roteamento com URLs que contêm pontos

Um modelo de rota padrão do lado do servidor pressupõe que, se o último segmento de uma URL de solicitação contiver um ponto (.) que um arquivo é solicitado. Por exemplo, a URL relativa /example/some.thing é interpretada pelo roteador como uma solicitação para um arquivo chamado some.thing. Sem configuração adicional, uma aplicação retorna uma resposta 404 - Não Encontrado se some.thing estiver direcionado para um componente com uma diretiva @page e some.thing for um valor atribuído ao parâmetro de rota. Para usar uma rota com um ou mais parâmetros que contêm um ponto, o aplicativo deve configurar a rota com um modelo personalizado.

Considere o seguinte componente Example que pode receber um parâmetro route do último segmento da 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 a aplicação Server de uma Blazor WebAssemblysolução hospedada processe pedidos que contenham um ponto no parâmetro da rota param, adicione um modelo de rota de ficheiro de fallback com o parâmetro opcional no ficheiro Program.

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

Para configurar uma aplicação Blazor Server para encaminhar a solicitação com um ponto no parâmetro de rota param, adicione um modelo de rota de página alternativa com o parâmetro opcional no ficheiro Program.

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

Para obter mais informações, consulte Roteamento no ASP.NET Core.

Para permitir que a aplicação Server de uma Blazor WebAssemblysolução hospedada processe a solicitação com um ponto no parâmetro de rota param, acrescente um modelo de rota de ficheiro de contingência com o parâmetro opcional em Startup.Configure.

Startup.cs:

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

Para configurar um aplicativo Blazor Server para redirecionar uma solicitação que contenha um ponto no parâmetro de rota param, adicione um modelo de rota alternativa para páginas, incluindo o parâmetro opcional em Startup.Configure.

Startup.cs:

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

Para obter mais informações, consulte Roteamento no ASP.NET Core.

Parâmetros de rota gerais

Os parâmetros de rota abrangentes, que capturam caminhos através de vários limites de pasta, são suportados nos componentes.

Os parâmetros de rota genéricos são:

  • Nomeado para corresponder ao nome do segmento de rota. A nomeação não faz distinção entre maiúsculas e minúsculas.
  • Um tipo string. A estrutura não fornece conversão automática.
  • No final da 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 o URL /catch-all/this/is/a/test com o modelo de rota /catch-all/{*pageRoute}, o valor de PageRoute é definido para this/is/a/test.

As barras (slashes) e segmentos do caminho capturado são decodificados. Para um modelo de rota de /catch-all/{*pageRoute}, a URL /catch-all/this/is/a%2Ftest%2A gera this/is/a/test*.

URI e auxiliares de estado de navegação

Use NavigationManager para gerenciar URIs e navegação em código C#. NavigationManager fornece o evento e os métodos mostrados na tabela a seguir.

Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra final) que pode ser prefixado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização do conteúdo <head>).
NavigateTo Navega até o URI especificado. Se forceLoad for false:
  • E a navegação aprimorada está disponível no URL atual, e a navegação aprimorada de Blazorestá ativada.
  • Caso contrário, Blazor executa uma recarga de página inteira para a URL solicitada.
Se forceLoad for true:
  • O roteamento do lado do cliente é evitado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser normalmente manipulado pelo roteador interativo do lado do cliente.

Para obter mais informações, consulte a seção Navegação aprimorada e manipulação de formulários .

Se replace estiver true, o URI atual no histórico do navegador será substituído em vez de enviar um novo URI para a pilha de histórico.

LocationChanged Um evento que é acionado quando a localização de navegação é alterada. Para obter mais informações, consulte a seção Alterações de Localização.
NotFound Chamado para lidar com cenários em que um recurso solicitado não é encontrado. Para obter mais informações, consulte a seção Respostas não encontradas .
ToAbsoluteUri Converte um URI relativo em um URI absoluto.
ToBaseRelativePath Com base no URI base do aplicativo, converte um URI absoluto em um URI relativo ao prefixo do URI base. Para um exemplo, consulte a seção Criar um URI relativo ao prefixo de URI base.
RegisterLocationChangingHandler Registra um manipulador para processar eventos de navegação de entrada. A chamada de NavigateTo invoca sempre o gestor.
GetUriWithQueryParameter Retorna um URI construído atualizando NavigationManager.Uri com um único parâmetro adicionado, atualizado ou removido. Para mais informações, consulte a seção sobre cadeias de caracteres de consulta.
Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra final) que pode ser prefixado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização do conteúdo <head>).
NavigateTo Navega até o URI especificado. Se forceLoad for false:
  • E a navegação aprimorada está disponível no URL atual, e a navegação aprimorada de Blazorestá ativada.
  • Caso contrário, Blazor executa uma recarga de página inteira para a URL solicitada.
Se forceLoad for true:
  • O roteamento do lado do cliente é evitado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser normalmente manipulado pelo roteador interativo do lado do cliente.

Para obter mais informações, consulte a seção Navegação aprimorada e manipulação de formulários .

Se replace estiver true, o URI atual no histórico do navegador será substituído em vez de enviar um novo URI para a pilha de histórico.

LocationChanged Um evento que é acionado quando a localização de navegação é alterada. Para obter mais informações, consulte a seção Alterações de Localização.
ToAbsoluteUri Converte um URI relativo em um URI absoluto.
ToBaseRelativePath Com base no URI base do aplicativo, converte um URI absoluto em um URI relativo ao prefixo do URI base. Para um exemplo, consulte a seção Criar um URI relativo ao prefixo de URI base.
RegisterLocationChangingHandler Registra um manipulador para processar eventos de navegação de entrada. A chamada de NavigateTo invoca sempre o gestor.
GetUriWithQueryParameter Retorna um URI construído atualizando NavigationManager.Uri com um único parâmetro adicionado, atualizado ou removido. Para mais informações, consulte a seção sobre cadeias de caracteres de consulta.
Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra final) que pode ser prefixado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização do conteúdo <head>).
NavigateTo Navega até o URI especificado. Se forceLoad for true:
  • O roteamento do lado do cliente é evitado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser normalmente manipulado pelo roteador do lado do cliente.
Se replace estiver true, o URI atual no histórico do navegador será substituído em vez de enviar um novo URI para a pilha de histórico.
LocationChanged Um evento que é acionado quando a localização de navegação é alterada. Para obter mais informações, consulte a seção Alterações de Localização.
ToAbsoluteUri Converte um URI relativo em um URI absoluto.
ToBaseRelativePath Com base no URI base do aplicativo, converte um URI absoluto em um URI relativo ao prefixo do URI base. Para um exemplo, consulte a seção Criar um URI relativo ao prefixo de URI base.
RegisterLocationChangingHandler Registra um manipulador para processar eventos de navegação de entrada. A chamada de NavigateTo invoca sempre o gestor.
GetUriWithQueryParameter Retorna um URI construído atualizando NavigationManager.Uri com um único parâmetro adicionado, atualizado ou removido. Para mais informações, consulte a seção sobre cadeias de caracteres de consulta.
Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra final) que pode ser prefixado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização do conteúdo <head>).
NavigateTo Navega até o URI especificado. Se forceLoad for true:
  • O roteamento do lado do cliente é evitado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser normalmente manipulado pelo roteador do lado do cliente.
Se replace estiver true, o URI atual no histórico do navegador será substituído em vez de enviar um novo URI para a pilha de histórico.
LocationChanged Um evento que é acionado quando a localização de navegação é alterada. Para obter mais informações, consulte a seção Alterações de Localização.
ToAbsoluteUri Converte um URI relativo em um URI absoluto.
ToBaseRelativePath Com base no URI base do aplicativo, converte um URI absoluto em um URI relativo ao prefixo do URI base. Para um exemplo, consulte a seção Criar um URI relativo ao prefixo de URI base.
GetUriWithQueryParameter Retorna um URI construído atualizando NavigationManager.Uri com um único parâmetro adicionado, atualizado ou removido. Para mais informações, consulte a seção sobre cadeias de caracteres de consulta.
Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra final) que pode ser prefixado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização do conteúdo <head>).
NavigateTo Navega até o URI especificado. Se forceLoad for true:
  • O roteamento do lado do cliente é evitado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser normalmente manipulado pelo roteador do lado do cliente.
LocationChanged Um evento que é acionado quando a localização de navegação é alterada.
ToAbsoluteUri Converte um URI relativo em um URI absoluto.
ToBaseRelativePath Com base no URI base do aplicativo, converte um URI absoluto em um URI relativo ao prefixo do URI base. Para um exemplo, consulte a seção Criar um URI relativo ao prefixo de URI base.

Alterações de localização

Para o evento LocationChanged, LocationChangedEventArgs fornece as seguintes informações sobre eventos de navegação:

O seguinte componente:

  • Navega até o componente Counter do aplicativo (Counter.razor) quando o botão é selecionado usando NavigateTo.
  • Gere o evento de mudança de localização inscrevendo-se em NavigationManager.LocationChanged.
    • O método HandleLocationChanged é desvinculado quando Dispose é chamado pelo framework. Desacoplar o método permite a recolha de lixo do componente.

    • A implementação do logger registra as seguintes informações quando o botão é selecionado:

      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 obter mais informações sobre o descarte de componentes, consulte ASP.NET Core Razor de descarte de componentes.

Para um redirecionamento durante a renderização estática do lado do servidor (SSR estático), NavigationManager depende do lançamento de um NavigationException que é capturado pela estrutura, que converte o erro em um redirecionamento. O código que existe após a chamada para NavigateTo não é chamado. Ao usar o Visual Studio, o depurador quebra na exceção, exigindo que você desmarque a caixa de seleção para Quebrar quando esse tipo de exceção é manipulado pelo usuário na interface do usuário do Visual Studio para evitar que o depurador pare para redirecionamentos futuros.

Você pode usar a <BlazorDisableThrowNavigationException> propriedade MSBuild definida como true no arquivo de projeto do aplicativo para optar por não lançar mais um NavigationExceptionarquivo . Além disso, o código após a chamada é NavigateTo executado quando não teria sido executado antes. Esse comportamento é habilitado por padrão no modelo de projeto .NET 10 ou posterior Blazor Web App :

<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>

Observação

No .NET 10 ou posterior, você pode optar por não lançar um NavigationException definindo a <BlazorDisableThrowNavigationException> propriedade MSBuild como true no arquivo de projeto do aplicativo. Para aproveitar a nova propriedade e comportamento do MSBuild, atualize o aplicativo para .NET 10 ou posterior.

Respostas não encontradas

NavigationManager fornece um NotFound método para lidar com cenários em que um recurso solicitado não é encontrado durante a renderização estática do lado do servidor (SSR estático) ou a renderização interativa global:

  • SSR estático: A chamada NotFound define o código de status HTTP como 404.

  • Renderização interativa: sinaliza o Blazor router (Router componente) para renderizar o conteúdo Não Encontrado.

  • Renderização de streaming: se a navegação aprimorada estiver ativa, a renderização de streaming renderizará o conteúdo Não Encontrado sem recarregar a página. Quando a navegação aprimorada é bloqueada, o framework redireciona para o conteúdo da Página Não Encontrada com um recarregamento da página.

Observação

A discussão a seguir menciona que um componente não encontrado Razor pode ser atribuído ao parâmetro Router do componente NotFoundPage. O parâmetro funciona em conjunto com NavigationManager.NotFound e é descrito em mais detalhes mais adiante nesta seção.

A renderização de streaming só pode renderizar componentes que tenham uma rota, como uma NotFoundPage atribuição (NotFoundPage="...") ou uma atribuição de página de middleware de reexecução de páginas de código de status (UseStatusCodePagesWithReExecute). DefaultNotFound O conteúdo 404 ("Not found" texto simples) não tem uma rota, portanto, não pode ser usado durante a renderização de streaming.

Observação

O fragmento de renderização Não Encontrado (<NotFound>...</NotFound>) não é suportado no .NET 10 ou posterior.

NavigationManager.NotFound A renderização de conteúdo usa o seguinte, independentemente de a resposta ter sido iniciada ou não (na ordem):

  • Se NotFoundEventArgs.Path estiver definido, renderize o conteúdo da página atribuída.
  • Se Router.NotFoundPage estiver definido, renderize a página atribuída.
  • Uma página de middleware para a reexecução de páginas com código de status, se estiver configurada.
  • Nenhuma ação se nenhuma das abordagens anteriores for adotada.

O middleware de reexecução de páginas de código de status com UseStatusCodePagesWithReExecute tem precedência sobre problemas de roteamento de endereços no navegador, como um URL incorreto digitado na barra de endereço do navegador ou a seleção de um link que não tenha ponto de extremidade no aplicativo.

Quando um componente é renderizado estaticamente (SSR estático) e NavigationManager.NotFound é chamado, o código de status 404 é definido na resposta:

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

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

Para fornecer conteúdo "Not Found" para renderização interativa global, utilize uma página "Not Found" (componente Razor).

Observação

O Blazor modelo de projeto inclui uma NotFound.razor página por padrão. Esta página é renderizada automaticamente sempre que NavigationManager.NotFound é chamada, tornando mais fácil lidar com rotas ausentes, proporcionando uma experiência consistente para o utilizador.

NotFound.razor:

<h1>Not Found</h1>

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

Atribua o NotFound componente ao parâmetro do NotFoundPage roteador. NotFoundPage suporta o roteamento que pode ser usado no middleware de reexecução para páginas de códigos de status, incluindo opções além do middleware padrão. Se o fragmento NotFound de renderização (<NotFound>...</NotFound>) for definido junto com NotFoundPage, a página terá prioridade mais alta.

No exemplo a seguir, o componente anterior NotFound está presente na pasta do Pages aplicativo e é passado para o NotFoundPage parâmetro:

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

Quando um componente é renderizado com um modo de renderização interativo global, a chamada NotFound sinaliza o Blazor roteador para renderizar o NotFound componente:

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

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

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

Você pode usar o OnNotFound evento para notificações quando NotFound é invocado. O evento só é disparado quando NotFound é chamado, não para qualquer resposta 404. Por exemplo, definir HttpContextAccessor.HttpContext.Response.StatusCode para 404 não ativa NotFound/OnNotFound.

As aplicações que implementam um router personalizado também podem usar NavigationManager.NotFound. O Roteador personalizado pode renderizar conteúdo "Não Encontrado" de duas fontes, dependendo do estado da resposta:

  • Independentemente do estado de resposta, o caminho de reexecução para a página pode ser usado passando-o para UseStatusCodePagesWithReExecute:

    app.UseStatusCodePagesWithReExecute(
        "/not-found", createScopeForStatusCodePages: true);
    
  • Quando a resposta tiver começado, o NotFoundEventArgs.Path pode ser usado subscrevendo o OnNotFoundEvent no router:

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

No exemplo de componentes a seguir:

  • O NotFoundContext serviço é injetado, juntamente com o NavigationManager.
  • Em OnInitializedAsync, HandleNotFound é um manipulador de eventos atribuído ao OnNotFound evento. HandleNotFound chama NotFoundContext.UpdateContext para definir um título e uma mensagem para o conteúdo Não Encontrado exibido pelo componente Router no componente Routes (Routes.razor).
  • Os componentes normalmente usariam um ID de um parâmetro route para obter um filme ou usuário de um armazenamento de dados, como um banco de dados. Nos exemplos a seguir, nenhuma entidade é retornada (null) para simular o que acontece quando uma entidade não é encontrada.
  • Quando nenhuma entidade é retornada para OnInitializedAsync, NavigationManager.NotFound é chamada, o que, por consequência, dispara o evento OnNotFound e o manipulador de eventos HandleNotFound. O conteúdo 'Não encontrado' é exibido pelo router.
  • O método HandleNotFound é desligado durante a remoção de componentes em IDisposable.Dispose.

Movie componente (Movie.razor):

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

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

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

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

        var movie = await GetMovie(Id);

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

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

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

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

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

User componente (User.razor):

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

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

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

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

        var user = await GetUser(Id);

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

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

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

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

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

Para alcançar os componentes anteriores numa demonstração local utilizando uma aplicação de teste, adicione entradas no componente NavMenu (NavMenu.razor) para chegar aos componentes Movie e User. Os IDs de entidade, passados como parâmetros de rota, no exemplo a seguir são valores fictícios, que não têm efeito porque não são realmente usados pelos componentes, os quais simulam a situação de não encontrar um filme ou usuário.

Em NavMenu.razor:

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

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

Navegação e manipulação de formulários aprimoradas

Esta seção aplica-se a Blazor Web Apps.

Blazor Web Apps são capazes de dois tipos de roteamento para navegação de página e solicitações de tratamento de formulário:

  • Navegação normal (navegação entre documentos): uma recarga de página inteira é acionada para o URL da solicitação.
  • Navegação melhorada (navegação no mesmo documento): Blazor interceta a solicitação e executa uma solicitação fetch em seu lugar. Blazor então insere o conteúdo da resposta no DOM da página. A navegação e o manuseio de formulários aprimorados do Blazorevitam a necessidade de recarregar a página inteira e preservam mais do estado da página, fazendo com que as páginas sejam carregadas mais rapidamente, geralmente sem perder a posição de rolagem do usuário na página.

A navegação melhorada está disponível quando:

  • O script Blazor Web App (blazor.web.js) é usado, não o script Blazor Server (blazor.server.js) ou Blazor WebAssembly script (blazor.webassembly.js).
  • A funcionalidade não está explicitamente desativada.
  • A URL de destino está dentro do espaço URI de base interno (o caminho base do aplicativo) e o link para a página não tem o data-enhance-nav atributo definido como false.

Se o roteamento no lado do servidor e a navegação aprimorada estiverem habilitados, os manipuladores de alteração de localização serão invocados apenas para navegação programática iniciada a partir de um tempo de execução interativo. Em versões futuras, tipos adicionais de navegação, como seguir um link, também podem invocar manipuladores de mudança de local.

Quando ocorre uma navegação avançada, os manipuladores de eventos LocationChanged registados nos runtimes do Interactive Server e WebAssembly normalmente são invocados. Há casos em que os manipuladores de alterações de localização podem não interceptar uma navegação aprimorada. Por exemplo, o usuário pode alternar para outra página antes que um tempo de execução interativo fique disponível. Portanto, é importante que a lógica do aplicativo não dependa da invocação de um manipulador de mudança de local, pois não há garantia de execução do manipulador.

Ao ligar para NavigateTo:

  • Se forceLoad é false, que é o padrão:
    • E a navegação aprimorada está disponível no URL atual, e a navegação aprimorada de Blazorestá ativada.
    • Caso contrário, Blazor executa uma recarga de página inteira para a URL solicitada.
  • Se forceLoad estiver true: Blazor executa uma recarga de página inteira para o URL solicitado, independentemente de a navegação aprimorada estar disponível ou não.

Você pode atualizar a página atual chamando NavigationManager.Refresh(bool forceLoad = false), que sempre executa uma navegação aprimorada, se disponível. Se a navegação aprimorada não estiver disponível, Blazor executará um recarregamento de página inteira.

Navigation.Refresh();

Passe true para o parâmetro forceLoad para garantir que uma recarga de página inteira seja sempre executada, mesmo que a navegação aprimorada esteja disponível:

Navigation.Refresh(true);

A navegação aprimorada é habilitada por padrão, mas pode ser controlada hierarquicamente e por link usando o atributo HTML data-enhance-nav.

Os exemplos a seguir desabilitam a navegação aprimorada:

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

Se o destino for um endpoint não-Blazor, a navegação aprimorada não se aplicará e o JavaScript do lado do cliente será tentado novamente como um carregamento de página completa. Isso garante que não haja confusão na estrutura sobre páginas externas que não devem ser corrigidas em uma página existente.

Para habilitar o tratamento avançado de formulários, adicione o parâmetro Enhance a formulários EditForm ou o atributo data-enhance a formulários HTML (<form>):

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

A manipulação aprimorada de formulários não é hierárquica e não se aplica a estruturas descendentes.

Sem suporte: Não é possível definir a navegação aprimorada no elemento ancestral de um formulário para habilitar a navegação aprimorada para o formulário.

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

As postagens de formulários melhoradas só funcionam com endpoints Blazor. A publicação de um formulário avançado para um endpoint que não seja oBlazor resulta em um erro.

Para desativar a navegação avançada:

  • Para uma EditForm, remova o parâmetro Enhance do elemento de formulário (ou defina-o como false: Enhance="false").
  • Para um HTML <form>, remova o atributo data-enhance do elemento de formulário (ou defina-o como false: data-enhance="false").

A navegação e o manuseamento de formulários melhorados do Blazorpodem reverter alterações dinâmicas no DOM se o conteúdo atualizado não fizer parte da renderização do servidor. Para preservar o conteúdo de um elemento, use o atributo data-permanent.

No exemplo a seguir, o conteúdo do elemento <div> é atualizado dinamicamente por um script quando a página é carregada:

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

Depois que Blazor for iniciado no cliente, você poderá usar o evento enhancedload para ouvir atualizações de página aprimoradas. Isso permite reaplicar alterações ao DOM que podem ter sido desfeitas por uma atualização de página aprimorada.

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

Para desativar a navegação aprimorada e a manipulação de formulários globalmente, consulte inicialização do ASP.NET Core.

A navegação melhorada com renderização estática no servidor (SSR estático) requer atenção especial ao carregar JavaScript. Para obter mais informações, consulte ASP.NET Core Blazor JavaScript com renderização estática do lado do servidor (SSR estático).

Produzir um URI relativo ao prefixo de URI base

Com base no URI base do aplicativo, ToBaseRelativePath converte um URI absoluto em um URI relativo ao prefixo do URI base.

Considere o seguinte exemplo:

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

Se o URI base da aplicação for https://localhost:8000, obtêm-se os seguintes resultados:

  • Passar https://localhost:8000/segment em inputURI resulta num baseRelativePath de segment.
  • Passar https://localhost:8000/segment1/segment2 em inputURI resulta num baseRelativePath de segment1/segment2.

Se o URI base da aplicação não corresponder ao URI base do inputURI, será gerada uma ArgumentException.

A passagem de https://localhost:8001/segment em inputURI resulta na seguinte exceção:

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

O NavigationManager usa a API de Histórico do navegador para manter o estado do histórico de navegação associado a cada alteração de localização feita pela aplicação. Manter o estado do histórico é particularmente útil em cenários de redirecionamento externo, como ao autenticar utilizadores com provedores de identidade externos. Para obter mais informações, consulte a seção Opções de navegação .

Passe NavigationOptions para NavigateTo para controlar os seguintes comportamentos:

  • ForceLoad: Ignore o roteamento do lado do cliente e force o navegador a carregar a nova página do servidor, independentemente de o URI ser ou não manipulado pelo roteador do lado do cliente. O valor padrão é false.
  • ReplaceHistoryEntry: Substitua a entrada atual no stack de histórico. Caso falseesteja presente, adiciona a nova entrada à pilha de histórico. O valor padrão é false.
  • HistoryEntryState: Obtém ou define o estado a ser anexado à entrada do histórico.
Navigation.NavigateTo("/path", new NavigationOptions
{
    HistoryEntryState = "Navigation state"
});

Para obter mais informações sobre como obter o estado associado à entrada do histórico de destino ao lidar com alterações de local, consulte a seção Manipular/impedir alterações de local.

Parâmetros de consulta

Use o atributo [SupplyParameterFromQuery] para especificar que um parâmetro de componente vem da cadeia de caracteres de consulta.

Use o atributo [SupplyParameterFromQuery] com o atributo [Parameter] para especificar que um parâmetro de componente de um componente roteável vem da cadeia de consulta.

Observação

Os parâmetros de componente só podem receber valores de parâmetros de pesquisa em componentes que podem ser roteados com uma diretiva @page.

Apenas os componentes roteáveis recebem diretamente parâmetros de consulta para evitar subverter o fluxo de informações de cima para baixo e tornar a ordem de processamento de parâmetros clara, tanto pela estrutura quanto pelo aplicativo. Esse design evita bugs sutis no código do aplicativo que foi escrito assumindo uma ordem de processamento de parâmetros específica. Você é livre para definir parâmetros em cascata personalizados ou atribuir diretamente a parâmetros de componentes regulares para passar valores de parâmetros de consulta para componentes não roteáveis.

Os parâmetros de componente fornecidos a partir da cadeia de caracteres de consulta suportam os seguintes tipos:

  • bool, DateTime, decimal, double, , floatGuid, int, longstring, .
  • Variantes anuláveis dos tipos anteriores.
  • Matrizes dos tipos anteriores, sejam elas anuláveis ou não anuláveis.

A formatação invariante de cultura correta é aplicada para o tipo dado (CultureInfo.InvariantCulture).

Especifique a propriedade [SupplyParameterFromQuery] do atributo Name para usar um nome de parâmetro de consulta diferente do nome do parâmetro do componente. No exemplo a seguir, o nome C# do parâmetro component é {COMPONENT PARAMETER NAME}. Um nome de parâmetro de consulta diferente foi especificado para o marcador de posição {QUERY PARAMETER NAME}:

Ao contrário das propriedades de parâmetros do componente ([Parameter]), as propriedades [SupplyParameterFromQuery] podem ser marcadas como private além de public.

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

Assim como as propriedades de parâmetro de componente ([Parameter]), as propriedades [SupplyParameterFromQuery] são sempre propriedades public no .NET 6/7. No .NET 8 ou posterior, [SupplyParameterFromQuery] propriedades podem ser marcadas como public ou private.

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

No exemplo a seguir com uma URL de /search?filter=scifi%20stars&page=3&star=LeVar%20Burton&star=Gary%20Oldman:

  • A propriedade Filter resulta em scifi stars.
  • A propriedade Page resulta em 3.
  • A matriz Stars é preenchida a partir de parâmetros de consulta chamados star (Name = "star") e resolve para LeVar Burton e Gary Oldman.

Observação

Os parâmetros da cadeia de caracteres de consulta no componente de página roteável seguinte também funcionam num componente não roteável sem uma diretiva @page (por exemplo, Search.razor para um componente partilhado Search usado noutros 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; }
}

Use GetUriWithQueryParameter para adicionar, alterar ou remover um ou mais parâmetros de consulta na URL atual:

@inject NavigationManager Navigation

...

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

Para o exemplo anterior:

  • O espaço reservado {NAME} especifica o nome do parâmetro de consulta. O marcador de posição {VALUE} especifica o valor como sendo de um tipo suportado. Os tipos suportados são listados mais adiante nesta seção.
  • Uma cadeia de caracteres é retornada igual à URL atual com um único parâmetro:
    • Adicionado se o nome do parâmetro de consulta não existir na URL atual.
    • Atualizado para o valor fornecido se o parâmetro de consulta existir na URL atual.
    • Removido se o tipo do valor fornecido for anulável e o valor for igual a null.
  • A formatação invariante de cultura correta é aplicada para o tipo dado (CultureInfo.InvariantCulture).
  • O nome e o valor do parâmetro de consulta são codificados por URL.
  • Todos os valores com o nome do parâmetro de consulta correspondente são substituídos se houver várias instâncias do tipo.

Chame GetUriWithQueryParameters para criar um URI construído a partir de Uri com vários parâmetros adicionados, atualizados ou removidos. Para cada valor, a estrutura usa value?.GetType() para determinar o tipo de tempo de execução para cada parâmetro de consulta e seleciona a formatação invariante de cultura correta. A estrutura gera um erro para tipos sem suporte.

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters({PARAMETERS})

O placeholder {PARAMETERS} é um IReadOnlyDictionary<string, object>.

Passe uma string URI para que GetUriWithQueryParameters gere um novo URI a partir de um URI fornecido, com múltiplos parâmetros adicionados, atualizados ou removidos. Para cada valor, a estrutura usa value?.GetType() para determinar o tipo de tempo de execução para cada parâmetro de consulta e seleciona a formatação invariante de cultura correta. A estrutura gera um erro para tipos sem suporte. Os tipos suportados são listados mais adiante nesta seção.

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters("{URI}", {PARAMETERS})
  • O marcador de posição {URI} é o URI com ou sem uma string de consulta.
  • O placeholder {PARAMETERS} é um IReadOnlyDictionary<string, object>.

Os tipos suportados são idênticos aos tipos suportados para restrições de rota:

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

Os tipos suportados incluem:

  • Variantes anuláveis dos tipos anteriores.
  • Matrizes dos tipos anteriores, sejam elas anuláveis ou não anuláveis.

Advertência

Com a compactação, que é habilitada por padrão, evite criar componentes interativos seguros (autenticados/autorizados) do lado do servidor que renderizam dados de fontes não confiáveis. As fontes não confiáveis incluem parâmetros de rota, cadeias de caracteres de consulta, dados de interoperabilidade JS e qualquer outra fonte de dados que um usuário de terceiros possa controlar (bancos de dados, serviços externos). Para obter mais informações, consulte orientações para ASP.NET Core BlazorSignalR e orientações para mitigação de ameaças para ASP.NET Core Blazor renderização interativa do lado do servidor.

Substitua o valor de um parâmetro de consulta quando o parâmetro já existir

Navigation.GetUriWithQueryParameter("full name", "Morena Baccarin")
URL atual URL gerado
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

Adicione um parâmetro e um valor de consulta quando o parâmetro não existir

Navigation.GetUriWithQueryParameter("name", "Morena Baccarin")
URL atual URL gerado
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

Remover um parâmetro de consulta quando o valor do parâmetro estiver null

Navigation.GetUriWithQueryParameter("full name", (string)null)
URL atual URL gerado
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/

Adicionar, atualizar e remover parâmetros de consulta

No exemplo a seguir:

  • name é removido, se houver.
  • Caso age não esteja presente, ele é adicionado com um valor de 25 (int). Se estiver presente, age é atualizado para um valor de 25.
  • eye color é adicionado ou atualizado para um valor de green.
Navigation.GetUriWithQueryParameters(
    new Dictionary<string, object?>
    {
        ["name"] = null,
        ["age"] = (int?)25,
        ["eye color"] = "green"
    })
URL atual URL gerado
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

Suporte para valores enumeráveis

No exemplo a seguir:

  • full name é adicionado ou atualizado para Morena Baccarin, um único valor.
  • ping parâmetros são adicionados ou substituídos por 35, 16, 87 e 240.
Navigation.GetUriWithQueryParameters(
    new Dictionary<string, object?>
    {
        ["full name"] = "Morena Baccarin",
        ["ping"] = new int?[] { 35, 16, null, 87, 240 }
    })
URL atual URL gerado
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

Para navegar com uma cadeia de caracteres de consulta adicionada ou modificada, passe uma URL gerada para NavigateTo.

O seguinte exemplo faz referência a:

  • GetUriWithQueryParameter adicionar ou substituir o parâmetro de consulta name usando um valor de Morena Baccarin.
  • Chamada NavigateTo para iniciar a navegação para o novo URL.
Navigation.NavigateTo(
    Navigation.GetUriWithQueryParameter("name", "Morena Baccarin"));

A seqüência de caracteres de consulta de uma solicitação é obtida da propriedade NavigationManager.Uri:

@inject NavigationManager Navigation

...

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

Para analisar os parâmetros de uma cadeia de caracteres de consulta, uma abordagem é usar URLSearchParams com interoperabilidade JavaScript (JS):

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

Para mais informações sobre o isolamento de JavaScript com módulos JavaScript, consulte Chamar funções JavaScript a partir de métodos .NET no ASP.NET Core Blazor.

Roteamento com hash para elementos identificados por nome

Navegue para um elemento específico usando as seguintes abordagens com uma referência em hash (#) ao elemento. Rotas para elementos dentro do componente, e rotas para elementos em componentes externos, utilizam caminhos relativos à raiz. Uma barra à frente no início (/) é opcional.

Exemplos de cada uma das abordagens seguintes demonstram a navegação até um elemento com id de targetElement no componente Counter.

  • Elemento de ancoragem (<a>) com um elemento href:

    <a href="/counter#targetElement">
    
  • Componente NavLink com um href:

    <NavLink href="/counter#targetElement">
    
  • NavigationManager.NavigateTo passando o URL relativo:

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

O exemplo a seguir demonstra o roteamento em hash para cabeçalhos H2 nomeados dentro de um componente e para componentes externos.

Nos componentes Home (Home.razor) e Counter (Counter.razor), coloque a seguinte marcação na parte inferior da marcação de componente existente para servir como destinos de navegação. O <div> cria espaço vertical artificial para demonstrar o comportamento de rolagem do navegador:

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

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

Adicione o seguinte componente HashedRouting ao aplicativo.

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

Interação do utilizador com conteúdo <Navigating>

Se houver um atraso significativo durante a navegação, como durante o carregamento lento de assemblies em um aplicativo Blazor WebAssembly ou para uma conexão de rede lenta com um aplicativo Blazor do lado do servidor, o componente Router pode indicar ao usuário que uma transição de página está ocorrendo.

Na parte superior do componente que especifica o componente Router, adicione uma diretiva @using para o namespace Microsoft.AspNetCore.Components.Routing:

@using Microsoft.AspNetCore.Components.Routing

Forneça conteúdo ao parâmetro Navigating para exibição durante eventos de transição de página.

No conteúdo do elemento do roteador (<Router>...</Router>):

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

Para obter um exemplo que usa a propriedade Navigating, consulte Lazy load assemblies in ASP.NET Core Blazor WebAssembly.

Manipular eventos de navegação assíncrona com OnNavigateAsync

O componente Router suporta um recurso OnNavigateAsync. O manipulador de OnNavigateAsync é invocado quando o usuário:

  • Visita uma rota pela primeira vez navegando até ela diretamente em seu navegador.
  • Navega para uma nova rota usando um link ou uma NavigationManager.NavigateTo invocação.
<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 obter um exemplo que usa OnNavigateAsync, consulte Conjuntos de carga lentos em ASP.NET Core Blazor WebAssembly.

Ao pré-renderizar no servidor, OnNavigateAsync é executado duas vezes:

  • Uma vez quando o componente de ponto de acesso solicitado é inicialmente renderizado de forma estática.
  • Quando o navegador renderiza o componente endpoint pela segunda vez.

Para evitar que o código do desenvolvedor no OnNavigateAsync seja executado duas vezes, o componente Routes pode armazenar o NavigationContext para uso no método de ciclo de vida OnAfterRender{Async}, onde firstRender pode ser verificado. Para obter mais informações, consulte Pré-renderização com JavaScript Interop.

Para evitar que o código do desenvolvedor no OnNavigateAsync seja executado duas vezes, o componente App pode armazenar o NavigationContext para uso no OnAfterRender{Async}, onde firstRender pode ser verificado. Para obter mais informações, consulte Pré-renderização com JavaScript Interop.

Lidar com cancelamentos em OnNavigateAsync

O objeto NavigationContext passado para o callback OnNavigateAsync contém um CancellationToken que se define quando ocorre um novo evento de navegação. O callback OnNavigateAsync deve ser acionado quando este token de cancelamento for ativado para evitar a execução do callback OnNavigateAsync em uma navegação obsoleta.

Se um usuário navega para um ponto de extremidade, mas navega imediatamente para um novo ponto de extremidade, o aplicativo não deve continuar executando o retorno de chamada OnNavigateAsync para o primeiro ponto de extremidade.

No exemplo a seguir:

  • O token de cancelamento é passado na chamada para PostAsJsonAsync, o que é capaz de cancelar o POST se o utilizador se afastar do endpoint /about.
  • O token de cancelamento é definido durante uma operação de pré-busca do produto se o usuário se afastar do endpoint /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);
            }
        }
    }
}

Observação

Não lançar se o token de cancelamento em NavigationContext for cancelado pode resultar em comportamento não intencional, como renderizar um componente de uma navegação anterior.

Lidar com/prevenir alterações de localização

RegisterLocationChangingHandler registra um manipulador para processar eventos de navegação de entrada. O contexto do manipulador fornecido pelo LocationChangingContext inclui as seguintes propriedades:

Um componente pode registrar vários manipuladores de alteração de localização no método de ciclo de vida OnAfterRender{Async}. A navegação invoca todos os manipuladores de mudança de local registrados em todo o aplicativo (em vários componentes), e qualquer navegação interna executa todos eles em paralelo. Além de NavigateTo, manipuladores são invocados:

  • Ao selecionar links internos, que são links que apontam para URLs dentro do caminho base da aplicação.
  • Ao navegar usando os botões avançar e voltar em um navegador.

Os manipuladores são executados apenas para navegação interna dentro da aplicação. Se o usuário selecionar um link que navega para um site diferente ou alterar a barra de endereço para um site diferente manualmente, os manipuladores de mudança de local não serão executados.

Implemente IDisposable e elimine manipuladores registados para os desinscrever. Para obter mais informações, consulte o descarte de componentes do ASP.NET CoreRazor.

Importante

Não tente executar tarefas de limpeza do DOM via interoperabilidade JavaScript (JS) ao lidar com mudanças de localização. Use o padrão MutationObserver em JS no cliente. Para obter mais informações, consulte Interoperabilidade do JavaScript do ASP.NET Core Blazor (JS interop).

No exemplo a seguir, é registado um manipulador para mudança de localização para eventos de navegação.

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

Como a navegação interna pode ser cancelada de forma assíncrona, várias chamadas sobrepostas para manipuladores registrados podem ocorrer. Por exemplo, várias chamadas de manipulador podem ocorrer quando o usuário seleciona rapidamente o botão Voltar em uma página ou seleciona vários links antes que uma navegação seja executada. Segue-se um resumo da lógica de navegação assíncrona:

  • Se algum manipulador de mudança de local for registrado, toda a navegação será inicialmente revertida e, em seguida, repetida se a navegação não for cancelada.
  • Se forem feitas solicitações de navegação sobrepostas, a solicitação mais recente sempre cancelará solicitações anteriores, o que significa o seguinte:
    • O aplicativo pode tratar várias seleções de botões para trás e para frente como uma única seleção.
    • Se o usuário selecionar vários links antes da navegação ser concluída, o último link selecionado determinará a navegação.

Para obter mais informações sobre como passar NavigationOptions para NavigateTo para controlar entradas e o estado da pilha de histórico de navegação, consulte a seção Opções de navegação.

Para obter código de exemplo adicional, consulte o NavigationManagerComponent no BasicTestApp (dotnet/aspnetcore, fonte de referência).

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam a ramificação padrão do repositório, que representa o desenvolvimento atual para a próxima versão do .NET. Para selecionar uma tag para uma versão específica, use a lista suspensa Alternar entre ramificações ou tags. Para obter mais informações, consulte Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

O componente NavigationLock interceta eventos de navegação desde que seja renderizado, efetivamente "bloqueando" qualquer navegação dada até que seja tomada uma decisão de prosseguir ou cancelar. Use NavigationLock quando a intercetação de navegação puder ser limitada à duração de vida de um componente.

NavigationLock parâmetros:

  • ConfirmExternalNavigation define uma caixa de diálogo do navegador para solicitar que o usuário confirme ou cancele a navegação externa. O valor padrão é false. A exibição da caixa de diálogo de confirmação requer a interação inicial do usuário com a página antes de acionar a navegação externa com o URL na barra de endereço do navegador. Para obter mais informações sobre o requisito de interação, consulte Janela: beforeunload evento.
  • OnBeforeInternalNavigation define um callback para eventos de navegação interna.

No componente seguinte NavLock:

  • Uma tentativa de seguir o link para o site da Microsoft deve ser confirmada pelo usuário antes que a navegação para https://www.microsoft.com seja bem-sucedida.
  • PreventNavigation é chamado para impedir que a navegação ocorra caso o utilizador não confirme a navegação através de uma chamada de interoperabilidade JavaScript (JS) que gera a caixa de diálogo .

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 obter um código de exemplo adicional, consulte o componente ConfigurableNavigationLock no BasicTestApp (fonte de referênciadotnet/aspnetcore).

Use um componente NavLink no lugar de elementos de hiperlink HTML (<a>) ao criar links de navegação. Um componente NavLink se comporta como um elemento <a>, exceto que ele alterna uma classe CSS active com base em se sua href corresponde à URL atual. A classe active ajuda um usuário a entender qual página é a página ativa entre os links de navegação exibidos. Opcionalmente, atribua um nome de classe CSS a NavLink.ActiveClass para aplicar uma classe CSS personalizada ao link renderizado quando a rota atual corresponder ao href.

Há duas opções NavLinkMatch que você pode atribuir ao atributo Match do elemento <NavLink>:

  • NavLinkMatch.All: O NavLink fica ativo quando corresponde ao URL atual, ignorando a cadeia de caracteres e o fragmento de consulta. Para incluir a correspondência na cadeia de caracteres/fragmento de consulta, use a Microsoft.AspNetCore.Components.Routing.NavLink.EnableMatchAllForQueryStringAndFragmentAppContext opção definida como true.
  • NavLinkMatch.Prefix (padrão ): O NavLink fica ativo quando corresponde a qualquer prefixo da URL atual.

Há duas opções NavLinkMatch que você pode atribuir ao atributo Match do elemento <NavLink>:

No exemplo anterior, o HomeNavLinkhref="" corresponde à URL inicial e só recebe a classe CSS active no caminho base padrão do aplicativo (/). O segundo NavLink recebe a classe active quando o usuário visita qualquer URL com um prefixo component (por exemplo, /component e /component/another-segment).

Para adotar uma lógica de correspondência personalizada, subclassifique NavLink e sobreponha o seu método ShouldMatch. Retorne true do método quando quiser aplicar a classe CSS active:

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

Atributos adicionais do componente NavLink são passados para a tag de âncora renderizada. No exemplo a seguir, o componente NavLink inclui o atributo target:

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

A seguinte marcação HTML é renderizada:

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

Advertência

Devido à maneira como o Blazor renderiza o conteúdo filho, a renderização de componentes NavLink dentro de um loop for requer uma variável de índice local, caso a variável do loop de incremento seja usada no conteúdo do componente NavLink (filho).

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

O uso de uma variável de índice neste cenário é um requisito para qualquer componente filho que use uma variável de loop no seu conteúdo filho , e não apenas o componente NavLink.

Como alternativa, use um loop de foreach com Enumerable.Range:

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

NavLink entradas de componentes podem ser criadas dinamicamente a partir dos componentes do aplicativo por meio de reflexão. O exemplo a seguir demonstra a abordagem geral para personalização adicional.

Para a demonstração a seguir, uma convenção de nomenclatura padrão consistente é usada para os componentes do aplicativo:

  • Os nomes de ficheiro de componentes routáveis usam Pascal case†, por exemplo, Pages/ProductDetail.razor.
  • Os caminhos de arquivo dos componentes roteáveis correspondem às suas URLs em kebab case‡, com hífenes colocados entre as palavras no modelo de rota de um componente. Por exemplo, um componente ProductDetail com um modelo de rota de /product-detail (@page "/product-detail") é solicitado em um navegador na URL relativa /product-detail.

Pascal Case (camel case superior) é uma convenção de nomenclatura sem espaços e pontuação, com a primeira letra de cada palavra em maiúscula, incluindo a primeira palavra.
‡Kebab case é uma convenção de nomenclatura sem espaços e pontuação que usa letras minúsculas e traços entre palavras.

Na marcação Razor do componente NavMenu (NavMenu.razor) na página padrão Home, os componentes NavLink são adicionados de uma coleção:

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

O método GetRoutableComponents no bloco @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);

O exemplo anterior não inclui as seguintes páginas na lista renderizada de componentes:

  • Home página: A página é listada separadamente dos links gerados automaticamente porque deve aparecer no topo da lista e definir o parâmetro Match.
  • Error página: A página de erro é acessada apenas pelo framework e não deve ser listada.

Para obter um exemplo do código anterior em um aplicativo de exemplo que você pode executar localmente, obtenha o Blazor Web App ou Blazor WebAssembly aplicativo de exemplo.

Integração de roteamento de endpoint do ASP.NET Core

Esta secção aplica-se aos Blazor Web Appque operam num circuito.

Esta secção aplica-se a aplicações Blazor Server.

Um Blazor Web App é integrado ao ASP.NET Core Endpoint Routing. Um aplicativo ASP.NET Core é configurado para aceitar conexões de entrada para componentes interativos com MapRazorComponents no arquivo Program. O componente raiz padrão (primeiro componente carregado) é o componente App (App.razor):

app.MapRazorComponents<App>();

Blazor Server está integrado no ASP.NET Core Endpoint Routing. Um aplicativo ASP.NET Core está configurado para aceitar conexões de entrada para componentes interativos com MapBlazorHub no arquivo Program:

app.UseRouting();

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

Blazor Server está integrado no ASP.NET Core Endpoint Routing. Um aplicativo ASP.NET Core está configurado para aceitar conexões de entrada para componentes interativos com MapBlazorHub no Startup.Configure.

A configuração típica é rotear todas as solicitações para uma página de Razor, que atua como o host para a parte do lado do servidor do aplicativo Blazor Server. Por convenção, a página host geralmente é nomeada _Host.cshtml na pasta Pages do aplicativo.

A rota especificada no ficheiro de anfitrião é chamada de rota de recurso porque opera com baixa prioridade na correspondência de rotas. A rota de fallback é usada quando outras rotas não correspondem. Isso permite que o aplicativo use outros controladores e páginas sem interferir com o roteamento de componentes no aplicativo Blazor Server.

Para obter informações sobre como configurar MapFallbackToPage para hospedagem de servidor com URL não raiz, consulte caminho base de aplicativos ASP.NET CoreBlazor.