Compartilhar via


Roteamento e navegação do Blazor do ASP.NET Core

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Aviso

Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

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

Importante

Exemplos de código ao longo deste artigo mostram métodos chamados no Navigation, que é um NavigationManager injetado em classes e componentes.

Roteamento estático versus interativo

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

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

Quando um modo de renderização interativa é atribuído ao componente Routes, o roteador Blazor se torna interativo após a SSR estática com o 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 da solicitação HTTP para determinar qual componente será renderizado. Quando o roteador se torna interativo, ele usa a URL do documento (a URL na barra de endereços do navegador) para determinar qual componente será renderizado. Isso significa que o roteador interativo pode alterar dinamicamente qual componente é renderizado se a URL do documento for alterada dinamicamente para outra URL interna válida e poderá fazê-lo sem executar uma solicitação HTTP para buscar o novo conteúdo da página.

O roteamento interativo também impede a pré-renderização porque o novo conteúdo da página não é solicitado do servidor com uma solicitação de página normal. Para mais informações, confira Pré-renderizar componentes Razor do ASP.NET Core.

Modelos de rota

O componente Router habilita o roteamento para componentes Razore está localizado no componente Routes do aplicativo (Components/Routes.razor).

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

Quando um Razorcomponente (.razor) com uma @pagediretiva é compilado, a classe de componente gerada recebe um RouteAttribute que especifica o modelo de rota do componente.

Quando o aplicativo é iniciado, o assembly especificado como AppAssembly do Roteador é verificado para a coleta de informações de rota para os componentes do aplicativo que têm um RouteAttribute.

Em runtime, o componente RouteView:

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

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

Os componentes dão suporte a vários modelos de rota usando várias @page diretivas. 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 resolvam corretamente, o aplicativo precisa incluir uma marcação de <base> (local do conteúdo <head>) com o caminho base do aplicativo especificado no atributo href . Para obter mais informações, confira Hospedar e implantar Blazor do ASP.NET Core.

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

Como alternativa para especificar o modelo de rota como um literal de cadeia de caracteres com a diretiva @page, modelos de rota baseados em constante podem ser especificados com a @attribute diretiva.

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

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

Observação

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

Concentrar um elemento na navegação

O componente FocusOnNavigate define o foco da interface do usuário em um elemento com base 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 no cabeçalho de nível superior da página (<h1>). Essa é uma estratégia comum para garantir que uma navegação de página será anunciada no uso de um leitor de tela.

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

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

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

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

Há suporte para itens arbitrários como conteúdo do parâmetro NotFound, como outros componentes interativos. Para aplicar um layout padrão ao conteúdo de NotFound, confira Layouts do ASP.NET Core Blazor.

Importante

Os Blazor Web App não usam o parâmetro NotFound (marcação <NotFound>...</NotFound>), mas o parâmetro tem suporte para compatibilidade com versões anteriores, a fim de evitar uma alteração interruptiva na estrutura. O pipeline de middleware ASP.NET Core do lado do servidor processa solicitações no servidor. Use as técnicas do servidor para tratar as solicitações incorretas. Para obter mais informações, consulte ASP.NET Core Blazor modos de renderização.

Rotear para componentes de vários assemblies

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

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

Roteamento estático

Para descobrir componentes roteáveis de assemblies adicionais para SSR estática, mesmo que o roteador mais tarde se torne interativo para renderização interativa, os assemblies deverão ser divulgados para a estrutura Blazor. Chame o método AddAdditionalAssemblies com os assemblies adicionais encadeados ao MapRazorComponents no arquivo Program do projeto do servidor.

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

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

Observação

As diretrizes anteriores também se aplicam em cenários de biblioteca de classes de componente. Diretrizes importantes adicionais para bibliotecas de classes e SSR estática são encontradas nas bibliotecas de classes (RCLs) Razor do ASP.NET Core com renderização estática do lado do servidor (SSR estática).

Roteamento interativo

Um modo de renderização interativo pode ser atribuído ao componente Routes (Routes.razor) que torna o roteador Blazor interativo após a SSR estática e o roteamento estático no servidor. Por exemplo, <Routes @rendermode="InteractiveServer" /> atribui a renderização interativa do lado do servidor (SSR interativa) ao componente Routes. O componente Router herda a renderização interativa do lado do servidor (SSR interativa) 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áginas internas. Para mais informações, confira Pré-renderizar componentes Razor do ASP.NET Core.

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

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

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

Assemblies adicionais são verificados além do assembly especificado para AppAssembly.

Observação

As diretrizes anteriores também se aplicam em cenários de biblioteca de classes de componente.

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 do servidor. Nesse caso, não há assemblies externos com componentes roteáveis, portanto, não é necessário especificar um valor para AdditionalAssemblies.

Esta seção aplica-se a aplicativos Blazor Server.

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

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

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

Assemblies adicionais são verificados além do assembly especificado para AppAssembly.

Parâmetros de rota

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

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

Não há suporte a parâmetros posicionais. No exemplo a seguir, duas @page diretivas 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 vidaOnInitialized{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 navega 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, confira a seção Cadeias de caracteres de consulta.

Restrições da rota

Uma restrição de rota impõe a correspondência de tipo em um segmento de rota a um componente.

No exemplo a seguir, a rota para o componente User só terá correspondência se:

  • Um segmento de rota Id está presente na URL de 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

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

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

Restrição Exemplo Correspondências de exemplo Invariável
cultura
correspondência
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} Não BlazorSample.styles.css, não favicon.ico Sim

Aviso

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

As restrições de rota também funcionam com parâmetros opcionais. No exemplo a seguir, Id é obrigatório, mas Option é um parâmetro de rota booliano 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 a captura de arquivos em um 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 para capturar caminhos que não são 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 (.), um arquivo será solicitado. Por exemplo, a URL relativa /example/some.thing é interpretada pelo roteador como uma solicitação de um arquivo chamado some.thing. Sem configuração adicional, um aplicativo retornará uma resposta 404 – Não encontrado se some.thing devesse rotear para um componente com uma diretiva @page e some.thing é um valor de parâmetro de rota. Para usar uma rota com um ou mais parâmetros que contenham um ponto, o aplicativo precisará configurar a rota com um modelo personalizado.

Considere o componente Example a seguir que pode receber um parâmetro de rota 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 o aplicativo Server de uma solução Blazor WebAssembly hospedada encaminhe a solicitação com um ponto no parâmetro de rota param, adicione um modelo de rota de arquivo de fallback com o parâmetro opcional no arquivo Program:

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

Para configurar um aplicativo Blazor Server para rotear a solicitação com um ponto no parâmetro de rota param, adicione um modelo de rota de página de fallback com o parâmetro opcional no arquivo Program:

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

Saiba mais em Roteamento no ASP.NET Core.

Para permitir que o aplicativo Server de uma solução Blazor WebAssemblyhospedada encaminhe a solicitação com um ponto no parâmetro de rota param, adicione um modelo de rota de arquivo de fallback com o parâmetro opcional em Startup.Configure.

Startup.cs:

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

Para configurar um aplicativo Blazor Server para rotear a solicitação com um ponto no parâmetro de rota param, adicione um modelo de rota de página de fallback com o parâmetro opcional em Startup.Configure.

Startup.cs:

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

Saiba mais em Roteamento no ASP.NET Core.

Parâmetros de rota catch-all

Os parâmetros de rota catch-all, que capturam caminhos entre vários limites de pasta, têm suporte nos componentes.

Os parâmetros de rota catch-all são:

  • Nomeados de forma a corresponder ao nome do segmento de rota. A nomenclatura não diferencia maiúsculas de 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 /catch-all/this/is/a/test de URL com um modelo de rota de /catch-all/{*pageRoute}, o valor de PageRoute é definido como this/is/a/test.

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

Auxiliares de estado de navegação e URI

Use NavigationManager para gerenciar URIs e navegação no 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 à direita) que pode ser anexado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização de conteúdo de <head>).
NavigateTo Navega até o URI especificado. forceLoad se false:
  • E a navegação aprimorada estiver disponível na URL atual, a navegação aprimorada de Blazor será ativada.
  • Caso contrário, Blazor executará um recarregamento de página inteira para a URL solicitada.
forceLoad se true:
  • O roteamento do lado do cliente é ignorado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser tratado normalmente ou não pelo roteador interativo do lado do cliente.

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

Se replace for 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 o local de navegação é alterado. Para obter mais informações, confira a seção Alterações de local.
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 de URI base. Para obter um exemplo, consulte a seção Produzir um URI relativo ao prefixo de URI base.
RegisterLocationChangingHandler Registra um manipulador para processar eventos de navegação recebidos. A chamada de NavigateTo sempre invoca o manipulador.
GetUriWithQueryParameter Retorna um URI construído atualizando NavigationManager.Uri com um único parâmetro adicionado, atualizado ou removido. Para obter mais informações, confira a seção Cadeias de caracteres de consulta.
Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra à direita) que pode ser anexado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização de conteúdo de <head>).
NavigateTo Navega até o URI especificado. forceLoad se true:
  • O roteamento do lado do cliente é ignorado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser tratado normalmente ou não pelo roteador do lado do cliente.
Se replace for 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 o local de navegação é alterado. Para obter mais informações, confira a seção Alterações de local.
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 de URI base. Para obter um exemplo, consulte a seção Produzir um URI relativo ao prefixo de URI base.
RegisterLocationChangingHandler Registra um manipulador para processar eventos de navegação recebidos. A chamada de NavigateTo sempre invoca o manipulador.
GetUriWithQueryParameter Retorna um URI construído atualizando NavigationManager.Uri com um único parâmetro adicionado, atualizado ou removido. Para obter mais informações, confira a seção Cadeias de caracteres de consulta.
Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra à direita) que pode ser anexado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização de conteúdo de <head>).
NavigateTo Navega até o URI especificado. forceLoad se true:
  • O roteamento do lado do cliente é ignorado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser tratado normalmente ou não pelo roteador do lado do cliente.
Se replace for 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 o local de navegação é alterado. Para obter mais informações, confira a seção Alterações de local.
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 de URI base. Para obter um exemplo, consulte a seção Produzir 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 obter mais informações, confira a seção Cadeias de caracteres de consulta.
Membro Descrição
Uri Obtém o URI absoluto atual.
BaseUri Obtém o URI base (com uma barra à direita) que pode ser anexado a caminhos de URI relativos para produzir um URI absoluto. Normalmente, BaseUri corresponde ao atributo href no elemento <base> do documento (localização de conteúdo de <head>).
NavigateTo Navega até o URI especificado. forceLoad se true:
  • O roteamento do lado do cliente é ignorado.
  • O navegador é forçado a carregar a nova página do servidor, independentemente de o URI ser tratado normalmente ou não pelo roteador do lado do cliente.
LocationChanged Um evento que é acionado quando o local de navegação é alterado.
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 de URI base. Para obter um exemplo, consulte a seção Produzir 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.
  • Manipula o evento com alteração de local pela assinatura de NavigationManager.LocationChanged.
    • O método HandleLocationChanged é desconectado quando Dispose é chamado pela estrutura. A desconexão do método permite a coleta de lixo do componente.

    • A implementação do agente 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 Ciclo de vida do componente Razor do ASP.NET Core.

Navegação e tratamento de formulários aprimorados

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

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

  • Navegação normal (navegação entre documentos): um recarregamento de página inteira é disparado para a URL de solicitação.
  • Navegação aprimorada (navegação no mesmo documento): Blazor intercepta a solicitação e, em vez disso, executa uma solicitação fetch. Em seguida, Blazor aplica o patch do conteúdo de resposta no DOM da página. A navegação aprimorada e o tratamento de formulários de Blazor evitam a necessidade de um recarregamento de página inteira e preservam mais do estado da página, de modo que as páginas são carregadas mais rapidamente, sem perder a posição de rolagem do usuário na página.

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

  • O script do Blazor Web App (blazor.web.js) é usado, não o script do Blazor Server (blazor.server.js) ou o script do Blazor WebAssembly (blazor.webassembly.js).
  • O recurso não está desabilitado explicitamente.
  • A URL de destino está dentro do espaço interno do URI de base (o caminho base do aplicativo).

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

Quando ocorre uma navegação aprimorada, os manipuladores de eventos LocationChanged registrados junto ao Servidor Interativo e os runtimes do WebAssembly costumam ser invocados. Existem casos em que os manipuladores de alteração de localização poderão não interceptar uma navegação aprimorada. Por exemplo, o usuário poderá alternar para outra página antes de um runtime interativo ficar disponível. Portanto, é importante que a lógica do aplicativo não dependa da invocação de um manipulador de alteração de localização, já que não há garantia de execução do manipulador.

Ao chamar NavigateTo:

  • Se forceLoad for false, que é o padrão:
    • E a navegação aprimorada estiver disponível na URL atual, a navegação aprimorada de Blazor será ativada.
    • Caso contrário, Blazor executará um recarregamento de página inteira para a URL solicitada.
  • Se forceLoad for true: Blazor executará um carregamento de página inteira para a URL solicitada, 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 um recarregamento de página inteira seja sempre executada, mesmo se a navegação aprimorada estiver disponível:

Navigation.Refresh(true);

A navegação aprimorada está habilitada por padrão, mas pode ser controlada hierarquicamente e por link utilizando 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 ponto de extremidade diferente de Blazor, a navegação aprimorada não será aplicada e o JavaScript do lado do cliente se repetirá como um carregamento de toda a página. Isso garante que não haja nenhuma confusão na estrutura sobre páginas externas que não devem ser corrigidas em uma página existente.

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

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

O tratamento aprimorado de formulários não é hierárquico e não flui para os formulários secundários:

Não suportado: não é possível definir a navegação aprimorada em um elemento ancestral do formulário para habilitar a navegação aprimorada para o formulário.

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

As postagens do formulário aprimorado só funcionam com pontos de extremidade Blazor. A postagem de um formulário aprimorado em um ponto de extremidade diferente de Blazor resulta em um erro.

Para desabilitar a navegação aprimorada:

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

A navegação aprimorada e o manuseio de formulários da Blazor podem desfazer 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, utilize 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>

Uma vez que Blazor tenha sido iniciado no cliente, você poderá utilizar o evento enhancedload para escutar as atualizações aprimoradas da página. Isso permite a reaplicação de alterações no DOM que podem ter sido desfeitas por uma atualização de página aprimorada.

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

Para desabilitar a navegação aprimorada e o tratamento de formulários globalmente, consulte ASP.NET Core Blazor inicialização.

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

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 de URI base.

Considere o exemplo a seguir:

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

Se o URI base do aplicativo for https://localhost:8000, os seguintes resultados serão obtidos:

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

Se o URI base do aplicativo não corresponder ao URI base de inputURI, um ArgumentException será gerado.

Passar https://localhost:8001/segment em inputURI resulta na exceção a seguir:

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 local feita pelo aplicativo. Manter o estado do histórico é particularmente útil em cenários de redirecionamento externo, por exemplo, ao autenticar usuários com provedores de identity externos. Para obter mais informações, confira a seção Opções de Navegação.

Transmita NavigationOptions a NavigateTo para controlar os seguintes comportamentos:

  • ForceLoad: ignora o roteamento do lado do cliente e força o navegador a carregar a nova página do servidor, independentemente de o URI ser manipulado pelo roteador do lado do cliente. O valor padrão é false.
  • ReplaceHistoryEntry: substitui a entrada atual na pilha de histórico. Se false, acrescente a nova entrada à pilha de histórico. O valor padrão é false.
  • HistoryEntryState: obtém ou define o estado a ser acrescentado à entrada de histórico.
Navigation.NavigateTo("/path", new NavigationOptions
{
    HistoryEntryState = "Navigation state"
});

Para obter mais informações sobre como obter o estado associado à entrada de histórico de destino durante o tratamento de alterações de local, confira a seção Manipular/impedir alterações de local.

Cadeias de consulta

Use o atributo [SupplyParameterFromQuery] para especificar que um parâmetro de componente é proveniente 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 pode vir da cadeia de caracteres de consulta.

Observação

Os parâmetros de componente só podem receber valores de parâmetro de consulta em componentes roteáveis com uma diretiva @page.

Somente os componentes roteáveis recebem diretamente parâmetros de consulta para evitar subverter o fluxo de informações de cima para baixo e tornar clara a ordem de processamento de parâmetros, 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âmetro 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âmetro de consulta para componentes não roteáveis.

Os parâmetros de componente fornecidos da cadeia de caracteres de consulta dão suporte aos seguintes tipos:

  • bool, DateTime, decimal, double, float, Guid, int, long, string.
  • Variantes anuláveis dos tipos anteriores.
  • Matrizes dos tipos anteriores, sejam anuláveis, sejam não anuláveis.

A formatação sem variação de cultura correta é aplicada ao tipo determinado (CultureInfo.InvariantCulture).

Especifique a propriedade Name do atributo [SupplyParameterFromQuery] 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 de componente é {COMPONENT PARAMETER NAME}. Um nome de parâmetro de consulta diferente é especificado para o espaço reservado {QUERY PARAMETER NAME}:

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

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

Assim como as propriedades do parâmetro do componente ([Parameter]), as propriedades [SupplyParameterFromQuery] são sempre propriedades public no .NET 6/7. No .NET 8 ou posteriores, as propriedades [SupplyParameterFromQuery] podem ser marcadas 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 resolve scifi stars.
  • A propriedade Page resolve 3.
  • A matriz Stars é preenchida com base em parâmetros de consulta chamados star (Name = "star") e resolve para LeVar Burton e Gary Oldman.

Observação

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

No exemplo anterior:

  • O espaço reservado {NAME} especifica o nome do parâmetro de consulta. O espaço reservado {VALUE} especifica o valor como um tipo com suporte. Os tipos com suporte são listados posteriormente 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 null.
  • A formatação sem variação de cultura correta é aplicada ao tipo determinado (CultureInfo.InvariantCulture).
  • O nome e o valor do parâmetro de consulta são codificados em URL.
  • Todos os valores com o nome do parâmetro de consulta correspondente serão substituídos se houver várias instâncias do tipo.

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

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters({PARAMETERS})

O espaço reservado {PARAMETERS} é um IReadOnlyDictionary<string, object>.

Transmita uma cadeia de caracteres de URI para GetUriWithQueryParameters a fim de gerar um novo URI de um URI fornecido com vários parâmetros adicionados, atualizados ou removidos. Para cada valor, a estrutura usa value?.GetType() a fim de determinar o tipo de runtime para cada parâmetro de consulta e seleciona a formatação invariável da cultura correta. A estrutura lança um erro para tipos sem suporte. Os tipos com suporte são listados posteriormente nesta seção.

@inject NavigationManager Navigation

...

Navigation.GetUriWithQueryParameters("{URI}", {PARAMETERS})
  • O espaço reservado {URI} é o URI com ou sem uma cadeia de caracteres de consulta.
  • O espaço reservado {PARAMETERS} é um IReadOnlyDictionary<string, object>.

Os tipos com suporte são idênticos aos tipos com suporte em restrições de rota:

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

Os tipos compatíveis incluem:

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

Aviso

Com a compressão, que está 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 interoperação com 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 ASP.NET Core BlazorSignalRDiretrizes e Orientações de mitigação de ameaças para o ASP.NET Core Blazor renderização interativa do lado do servidor.

Substitui um valor de parâmetro de consulta quando o parâmetro existe

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

Acrescenta um parâmetro de consulta e um valor quando o parâmetro não existe

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

Remove um parâmetro de consulta quando o valor do parâmetro é null

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

Adiciona, atualiza e remove parâmetros de consulta

No exemplo a seguir:

  • name é removido, se presente.
  • age é adicionado com um valor de 25 (int), se não estiver presente. Se estiver presente, age será 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 gerada
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 a valores enumeráveis

No exemplo a seguir:

  • full name é adicionado ou atualizado para Morena Baccarin, um valor único.
  • 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 gerada
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, transmita uma URL gerada a NavigateTo.

O exemplo abaixo chama:

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

A cadeia 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 consulta, uma abordagem é usar URLSearchParams com interoperabilidade JavaScript (JS):

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

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

Roteamento de hash para elementos nomeados

Navegue até um elemento nomeado usando as abordagens a seguir com uma referência de hash (#) ao elemento. As rotas para elementos dentro do componente e as rotas para elementos em componentes externos usam caminhos relativos à raiz. Uma barra à esquerda (/) é opcional.

Exemplos para cada uma das abordagens a seguir demonstram a navegação para um elemento com um id do targetElement no componente Counter:

  • Elemento âncora (<a>) com um href:

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

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

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

O exemplo a seguir demonstra o roteamento hash para títulos H2 nomeados dentro de um componente e para componentes externos.

Nos componentes Home (Home.razor) e Counter (Counter.razor), coloque a marcação a seguir na parte inferior da marcação de componente existente para servir como destinos de navegação. O <div> cria um 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 componente HashedRouting a seguir 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 usuário 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 poderá 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 roteador (<Router>...</Router>):

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

Para obter um exemplo que usa a propriedade Navigating, confira Assemblies de carga lentos no ASP.NET Core Blazor WebAssembly.

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

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

  • Visita uma rota pela primeira vez navegando até ela diretamente no navegador.
  • Navega até uma nova rota usando um link ou uma invocação 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 obter um exemplo que usa a propriedade OnNavigateAsync, confira Assemblies de carga lentos no Blazor WebAssembly do ASP.NET Core.

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

  • Uma vez, quando o componente de ponto de extremidade solicitado é inicialmente renderizado estaticamente.
  • Uma segunda vez quando o navegador renderiza o componente do ponto de extremidade.

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

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

Manipular cancelamentos em OnNavigateAsync

O objeto NavigationContext transmitido ao retorno de chamada OnNavigateAsync contém um CancellationToken definido quando ocorre um novo evento de navegação. O retorno de chamada OnNavigateAsync precisa lançar quando esse token de cancelamento é definido a fim de evitar continuar a executar o retorno de chamada OnNavigateAsync em uma navegação desatualizada.

Se um usuário navegar até um ponto de extremidade, mas depois navegar imediatamente até um novo ponto de extremidade, o aplicativo não deverá continuar executando o retorno de chamada OnNavigateAsync para o primeiro ponto de extremidade.

No exemplo a seguir:

  • O token de cancelamento é transmitido na chamada a PostAsJsonAsync, o que pode cancelar o POST se o usuário navegar para longe do ponto de extremidade /about.
  • O token de cancelamento é definido durante uma operação de pré-busca do produto se o usuário navegar para longe do ponto de extremidade /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 poderá resultar em um comportamento não intencional, como a renderização de um componente de uma navegação anterior.

Manipular/impedir alterações de local

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

Um componente pode registrar vários manipuladores de alteração de local no método de ciclo de vida OnAfterRender{Async}. A navegação invoca todos os manipuladores de alteração de local registrados em todo o aplicativo (em vários componentes) e toda as navegações internas executam todos eles em paralelo. Além de NavigateTo, os manipuladores são invocados:

  • Ao selecionar links internos, que são links que apontam para URLs no caminho base do aplicativo.
  • Ao navegar usando os botões para frente e para trás em um navegador.

Os manipuladores são executados apenas para navegação interna dentro do aplicativo. Se o usuário selecionar um link que navegue até um site diferente ou alterar a barra de endereços para um site diferente manualmente, os manipuladores de alteração de localização não serão executados.

Implemente IDisposable e descarte manipuladores registrados para cancelá-los. Para saber mais, consulte Ciclo de vida de renderização de Razor no ASP.NET Core.

Importante

Não tente executar tarefas de limpeza do DOM (Document Object Model) por meio da interoperabilidade JavaScript (JS) ao lidar com alterações de local. Use o padrão MutationObserver em JS no cliente. Para obter mais informações, confira Interoperabilidade ASP.NET Core Blazor JavaScript (interoperabilidade JS).

No exemplo a seguir, um manipulador de alteração de local é registrado 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, podem ocorrer várias chamadas sobrepostas a manipuladores registrados. 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 de uma navegação ser executada. Veja abaixo um resumo da lógica de navegação assíncrona:

  • Se algum manipulador de alteração de local for registrado, toda a navegação será inicialmente revertida e reproduzida 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ão Voltar e encaminhar como uma única seleção.
    • Se o usuário selecionar vários links antes da conclusão da navegação, o último link selecionado determinará a navegação.

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

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

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

O NavigationLock componente intercepta eventos de navegação desde que seja renderizado, efetivamente "bloqueando" qualquer navegação determinada até que seja tomada uma decisão de prosseguir ou cancelar. Use NavigationLock quando o escopo da interceptação de navegação puder ser definido como o tempo de vida de um componente.

Parâmetros de NavigationLock:

  • ConfirmExternalNavigation define um 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 do diálogo de confirmação requer a interação inicial do usuário com a página antes de disparar a navegação externa com a URL na barra de endereços do navegador. Para obter mais informações sobre o requisito de interação, confira Evento Window: beforeunload (documentação do MDN).
  • OnBeforeInternalNavigation define um retorno de chamada para eventos de navegação interna.

No seguinte componente NavLock:

  • Uma tentativa de seguir o link para o site da Microsoft precisa ser confirmada pelo usuário antes que a navegação até https://www.microsoft.com seja bem-sucedida.
  • PreventNavigation é chamado para impedir que a navegação ocorra se o usuário se recusar a confirmar a navegação por meio de uma chamada de interoperabilidade JavaScript (JS) que gera o JSconfirm 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, confira o componente ConfigurableNavigationLock no BasicTestApp (fonte de referência dotnet/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 pelo fato de alternar uma classe CSS active com base na correspondência ou não de href à 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 a fim de aplicar uma classe CSS personalizada ao link renderizado quando a rota atual corresponde ao href.

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

No exemplo anterior, o HomeNavLinkhref="" corresponde à URL home e recebe apenas 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).

Atributos de componente de NavLink adicionais são transmitidos à marcação 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>

Aviso

Devido à maneira como o Blazor renderiza o conteúdo filho, renderizar componentes NavLink dentro de um loop for requer uma variável de índice local se a variável de loop de incremento é usada no conteúdo do componente (filho) NavLink:

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

Usar uma variável de índice nesse cenário é um requisito para qualquer componente filho que use uma variável de loop em seu conteúdo filho, não apenas o componente NavLink.

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

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

As entradas do componente NavLink podem ser criadas dinamicamente a partir dos componentes do aplicativo por meio da 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 arquivo de componentes roteáveis usam o Pascal case†, por exemplo Pages/ProductDetail.razor.
  • Os caminhos de arquivo de componentes roteáveis correspondem às suas URLs em kebab case‡ com hifens aparecendo entre as palavras no modelo da rota de um componente. Por exemplo, um componente ProductDetail com um modelo de rota /product-detail (@page "/product-detail") é solicitado em um navegador na URL relativa /product-detail.

PascalCase† (camelCase iniciada por maiúscula) é uma convenção de nomenclatura sem espaços e pontuação e com a primeira letra de cada palavra maiúscula, incluindo a primeira palavra.
‡Kebab case é uma convenção de nomes sem espaços e pontuação que utiliza letras minúsculas e traços entre as 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:

  • Página Home: a página é listada separadamente dos links gerados automaticamente porque ela deve aparecer na parte superior da lista e definir o parâmetro Match.
  • Página Error: a página de erro é navegada apenas pela estrutura e não deve ser listada.

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

Integração de roteamento de ponto de extremidade do ASP.NET Core

Essa seção se aplica aos Blazor Web Apps que operam em um circuito.

Esta seção aplica-se a aplicativos Blazor Server.

O Blazor Web App é integrado ao Roteamento de Ponto de Extremidade do ASP.NET. Core. 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>();

O Blazor Server é integrado ao Roteamento de Ponto de Extremidade do ASP.NET. Core. Um aplicativo ASP.NET Core é configurado para aceitar conexões de entrada para componentes interativos com MapBlazorHub no arquivo Program:

app.UseRouting();

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

O Blazor Server é integrado ao Roteamento de Ponto de Extremidade do ASP.NET. Core. Um aplicativo ASP.NET Core é 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 Razor Page, que atua como o host do aplicativo Blazor Server do lado do servidor. Por convenção, a página host geralmente é nomeada _Host.cshtml na pasta Pages do aplicativo.

A rota especificada no arquivo de host é chamada de rota de fallback 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 no roteamento de componentes no aplicativo Blazor Server.

Para obter informações sobre como configurar o MapFallbackToPage para hospedagem de servidor de URL não raiz, confira Hospedar e implantar o ASP.NET Core Blazor.