Exibições parciais no ASP.NET Core

Por Steve Smith, Maher JENDOUBI, Rick Anderson e Scott Sauber

Uma exibição parcial é um arquivo de marcação Razor (.cshtml) sem uma diretiva de @page que renderiza a saída HTML dentro da saída processada de outro arquivo de marcação.

O termo exibição parcial é usado durante o desenvolvimento de um aplicativo do MVC — sempre que os arquivos de marcação são chamados de exibições — ou de um aplicativo do Razor Pages — sempre que os arquivos de marcação são chamados de páginas. Esse tópico se refere genericamente a exibições do MVC e às páginas do Razor Pages como arquivos de marcação.

Exibir ou baixar código de exemplo (como baixar)

Quando usar exibições parciais

Exibições parciais são uma maneira eficaz de:

  • Dividir arquivos de marcação grandes em componentes menores.

    Aproveitar a vantagem de trabalhar com cada parte isolada em uma exibição parcial em um arquivo de marcação grande e complexo, composto por diversas partes lógicas. O código no arquivo de marcação é gerenciável porque a marcação contém somente a estrutura de página geral e as referências a exibições parciais.

  • Reduzir a duplicação de conteúdo de marcação comum em arquivos de marcação.

    Quando os mesmos elementos de marcação são usados nos arquivos de marcação, uma exibição parcial remove a duplicação de conteúdo de marcação em um arquivo de exibição parcial. Quando a marcação é alterada na exibição parcial, ela atualiza a saída renderizada dos arquivos de marcação que usam a exibição parcial.

As exibições parciais não podem ser usadas para manter os elementos de layout comuns. Os elementos de layout comuns precisam ser especificados nos arquivos _Layout.cshtml.

Não use uma exibição parcial em que a lógica de renderização complexa ou a execução de código são necessárias para renderizar a marcação. Em vez de uma exibição parcial, use um componente de exibição.

Declarar exibições parciais

Uma exibição parcial é um arquivo de marcação .cshtml sem uma diretiva de @page mantida dentro da pasta Exibições (MVC) ou na pasta Páginas (Razor Pages).

No ASP.NET Core MVC, um ViewResult do controlador é capaz de retornar uma exibição ou uma exibição parcial. No Razor Pages, um PageModel pode retornar uma exibição parcial representada como um objeto de PartialViewResult. A referência e a renderização de exibições parciais são descritas na seção Referenciar uma exibição parcial.

Ao contrário da exibição do MVC ou da renderização de página, uma exibição parcial não executa _ViewStart.cshtml. Saiba mais em _ViewStart.cshtml, confira Layout no ASP.NET Core.

Nomes de arquivos de exibição parcial geralmente começam com um sublinhado (_). Essa convenção de nomenclatura não é obrigatória, mas ajuda a diferenciar visualmente as exibições parciais das exibições e das páginas.

Uma exibição parcial é um arquivo de marcação .cshtml mantido dentro da pasta Exibições.

Um ViewResult do controlador é capaz de retornar uma exibição ou uma exibição parcial. A referência e a renderização de exibições parciais são descritas na seção Referenciar uma exibição parcial.

Ao contrário da renderização da exibição do MVC, uma exibição parcial não executa _ViewStart.cshtml. Saiba mais em _ViewStart.cshtml, confira Layout no ASP.NET Core.

Nomes de arquivos de exibição parcial geralmente começam com um sublinhado (_). Essa convenção de nomenclatura não é obrigatória, mas ajuda a diferenciar visualmente as exibições parciais das exibições.

Referenciar uma exibição parcial

Usar uma exibição parcial em um PageModel do Razor Pages

No ASP.NET Core 2.0 ou 2.1, o seguinte método de manipulador renderiza a exibição parcial _AuthorPartialRP.cshtml para a resposta:

public IActionResult OnGetPartial() =>
    new PartialViewResult
    {
        ViewName = "_AuthorPartialRP",
        ViewData = ViewData,
    };

No ASP.NET Core 2.2 ou posterior, um método de manipulador pode, como alternativa, chamar o método Partial para produzir um objeto PartialViewResult:

public IActionResult OnGetPartial() =>
    Partial("_AuthorPartialRP");

Usar uma exibição parcial em um arquivo de marcação

Há várias maneiras de referenciar uma exibição parcial em um arquivo de marcação. É recomendável que os aplicativos usem uma das seguintes abordagens de renderização assíncrona:

Há duas maneiras de referenciar uma exibição parcial em um arquivo de marcação:

É recomendável que os aplicativos usem o Auxiliar de HTML assíncrono.

Auxiliar de marca parcial

O Auxiliar de Marca Parcial exige o ASP.NET Core 2.1 ou posterior.

O Auxiliar de Marca Parcial renderiza o conteúdo de forma assíncrona e usa uma sintaxe semelhante a HTML:

<partial name="_PartialName" />

Quando houver uma extensão de arquivo, o Auxiliar de Marca fará referência a uma exibição parcial que precisa estar na mesma pasta que o arquivo de marcação que chama a exibição parcial:

<partial name="_PartialName.cshtml" />

O exemplo a seguir faz referência a uma exibição parcial da raiz do aplicativo. Caminhos que começam com um til-barra (~/) ou uma barra (/) referem-se à raiz do aplicativo:

Razor Pages

<partial name="~/Pages/Folder/_PartialName.cshtml" />
<partial name="/Pages/Folder/_PartialName.cshtml" />

MVC

<partial name="~/Views/Folder/_PartialName.cshtml" />
<partial name="/Views/Folder/_PartialName.cshtml" />

O exemplo a seguir faz referência a uma exibição parcial com um caminho relativo:

<partial name="../Account/_PartialName.cshtml" />

Para obter mais informações, confira Ajudante de Tags Parcial no ASP.NET Core.

Auxiliar HTML assíncrono

Ao usar um Auxiliar HTML, a melhor prática é usar PartialAsync. PartialAsync retorna um tipo IHtmlContent encapsulado em um Task<TResult>. O método é referenciado prefixando a chamada em espera com um caractere @:

@await Html.PartialAsync("_PartialName")

Quando houver a extensão de arquivo, o Auxiliar de HTML fará referência a uma exibição parcial que precisa estar na mesma pasta que o arquivo de marcação que chama a exibição parcial:

@await Html.PartialAsync("_PartialName.cshtml")

O exemplo a seguir faz referência a uma exibição parcial da raiz do aplicativo. Caminhos que começam com um til-barra (~/) ou uma barra (/) referem-se à raiz do aplicativo:

Razor Pages

@await Html.PartialAsync("~/Pages/Folder/_PartialName.cshtml")
@await Html.PartialAsync("/Pages/Folder/_PartialName.cshtml")

MVC

@await Html.PartialAsync("~/Views/Folder/_PartialName.cshtml")
@await Html.PartialAsync("/Views/Folder/_PartialName.cshtml")

O exemplo a seguir faz referência a uma exibição parcial com um caminho relativo:

@await Html.PartialAsync("../Account/_LoginPartial.cshtml")

Como alternativa, é possível renderizar uma exibição parcial com RenderPartialAsync. Esse método não retorna um IHtmlContent. Ele transmite a saída renderizada diretamente para a resposta. Como não retorna nenhum resultado, o método precisa ser chamado dentro de um bloco de código Razor:

@{
    await Html.RenderPartialAsync("_AuthorPartial");
}

Como RenderPartialAsync transmite conteúdo renderizado, ele apresenta melhor desempenho em alguns cenários. Em situações cruciais para o desempenho, submeta a página a benchmark usando ambas as abordagens e use aquela que gera uma resposta mais rápida.

Auxiliar de HTML assíncrono

Partial e RenderPartial são os equivalentes síncronos de PartialAsync e RenderPartialAsync, respectivamente. Os equivalentes síncronos não são recomendados porque há cenários em que eles realizam deadlock. Os métodos síncronos estão programados para serem removidos em uma versão futura.

Importante

Se for necessário executar código, use um componente de exibição em vez de uma exibição parcial.

Chamar Partial ou RenderPartial resulta em um aviso do analisador do Visual Studio. Por exemplo, a presença de Partial produz a seguinte mensagem de aviso:

Uso de IHtmlHelper.Partial pode resultar em deadlocks de aplicativo. Considere usar o Auxiliar de Marca <parcial> ou IHtmlHelper.PartialAsync.

Substitua as chamadas para @Html.Partial por @await Html.PartialAsync ou o Auxiliar de Marca Parcial. Para obter mais informações sobre a migração do auxiliar de marca parcial, consulte Migrar de um auxiliar HTML.

Descoberta de exibição parcial

Quando uma exibição parcial é referenciada pelo nome sem uma extensão de arquivo, os seguintes locais são pesquisados na ordem indicada:

Razor Pages

  1. Pasta da página em execução no momento
  2. Grafo do diretório acima da pasta da página
  3. /Shared
  4. /Pages/Shared
  5. /Views/Shared

MVC

  1. /Areas/<Area-Name>/Views/<Controller-Name>
  2. /Areas/<Area-Name>/Views/Shared
  3. /Views/Shared
  4. /Pages/Shared
  1. /Areas/<Area-Name>/Views/<Controller-Name>
  2. /Areas/<Area-Name>/Views/Shared
  3. /Views/Shared

As convenções a seguir se aplicam à descoberta de exibição parcial:

  • Diferentes exibições parciais com o mesmo nome de arquivo são permitidos quando as exibições parciais estão em pastas diferentes.
  • Ao referenciar uma exibição parcial pelo nome sem uma extensão de arquivo e a exibição parcial está presente na pasta do chamador e na pasta Compartilhada, a exibição parcial na pasta do chamador fornece a exibição parcial. Se a exibição parcial não existir na pasta do chamador, ela será fornecida pela pasta Compartilhada. Exibições parciais na pasta Compartilhada são chamadas de exibições parciais compartilhadas ou exibições parciais padrão.
  • As exibições parciais podem ser encadeadas — uma exibição parcial pode chamar uma outra exibição parcial se uma referência circular não tiver sido formada pelas chamadas. Caminhos relativos sempre são relativos ao arquivo atual, não à raiz ou ao pai do arquivo.

Observação

Um sectionRazor definido em uma exibição parcial é invisível para os arquivos de marcação pai. A section só é visível para a exibição parcial na qual ela está definida.

Acessar dados de exibições parciais

Quando uma exibição parcial é instanciada, ela recebe uma cópia do dicionário ViewData do pai. As atualizações feitas nos dados dentro da exibição parcial não são persistidas na exibição pai. Alterações a ViewData em uma exibição parcial são perdidas quando a exibição parcial retorna.

O exemplo a seguir demonstra como transmitir uma instância de ViewDataDictionary para uma exibição parcial:

@await Html.PartialAsync("_PartialName", customViewData)

Você pode passar um modelo para uma exibição parcial. O modelo pode ser um objeto personalizado. Você pode passar um modelo com PartialAsync (renderiza um bloco de conteúdo para o chamador) ou RenderPartialAsync (transmite o conteúdo para a saída):

@await Html.PartialAsync("_PartialName", model)

Razor Pages

A marcação a seguir na amostra de aplicativo vem da página Pages/ArticlesRP/ReadRP.cshtml. A página contém duas exibições parciais. A segunda exibição parcial passa um modelo e ViewData para a exibição parcial. A sobrecarga do construtor ViewDataDictionary é usada para passar um novo dicionário ViewData, retendo ainda o dicionário ViewData existente.

@model ReadRPModel

<h2>@Model.Article.Title</h2>
@* Pass the author's name to Pages\Shared\_AuthorPartialRP.cshtml *@
@await Html.PartialAsync("../Shared/_AuthorPartialRP", Model.Article.AuthorName)
@Model.Article.PublicationDate

@* Loop over the Sections and pass in a section and additional ViewData to 
   the strongly typed Pages\ArticlesRP\_ArticleSectionRP.cshtml partial view. *@
@{
    var index = 0;

    foreach (var section in Model.Article.Sections)
    {
        await Html.PartialAsync("_ArticleSectionRP", 
                                section,
                                new ViewDataDictionary(ViewData)
                                {
                                    { "index", index }
                                });

        index++;
    }
}

Pages/Shared/_AuthorPartialRP.cshtml é a primeira exibição parcial mencionada pelo arquivo de marcação ReadRP.cshtml:

@model string
<div>
    <h3>@Model</h3>
    This partial view from /Pages/Shared/_AuthorPartialRP.cshtml.
</div>

Pages/ArticlesRP/_ArticleSectionRP.cshtml é a segunda exibição parcial mencionada pelo arquivo de marcação ReadRP.cshtml:

@using PartialViewsSample.ViewModels
@model ArticleSection

<h3>@Model.Title Index: @ViewData["index"]</h3>
<div>
    @Model.Content
</div>

MVC

A marcação a seguir na amostra de aplicativo mostra a exibição Views/Articles/Read.cshtml. A exibição contém duas exibições parciais. A segunda exibição parcial passa um modelo e ViewData para a exibição parcial. A sobrecarga do construtor ViewDataDictionary é usada para passar um novo dicionário ViewData, retendo ainda o dicionário ViewData existente.

@model PartialViewsSample.ViewModels.Article

<h2>@Model.Title</h2>
@* Pass the author's name to Views\Shared\_AuthorPartial.cshtml *@
@await Html.PartialAsync("_AuthorPartial", Model.AuthorName)
@Model.PublicationDate

@* Loop over the Sections and pass in a section and additional ViewData to 
   the strongly typed Views\Articles\_ArticleSection.cshtml partial view. *@
@{
    var index = 0;

    foreach (var section in Model.Sections)
    {
        @(await Html.PartialAsync("_ArticleSection", 
                                section,
                                new ViewDataDictionary(ViewData)
                                {
                                    { "index", index }
                                }))

        index++;
    }
}

Views/Shared/_AuthorPartial.cshtml é a primeira exibição parcial mencionada pelo arquivo de marcação Read.cshtml:

@model string
<div>
    <h3>@Model</h3>
    This partial view from /Views/Shared/_AuthorPartial.cshtml.
</div>

Views/Articles/_ArticleSection.cshtml é a segunda exibição parcial mencionada pelo arquivo de marcação Read.cshtml:

@using PartialViewsSample.ViewModels
@model ArticleSection

<h3>@Model.Title Index: @ViewData["index"]</h3>
<div>
    @Model.Content
</div>

No runtime, as exibições parciais são renderizadas para a saída renderizada do arquivo de marcação pai que, por sua vez, é renderizado dentro do _Layout.cshtml compartilhado. A primeira exibição parcial renderiza a data de publicação e o nome do autor do artigo:

Abraham Lincoln

Esta exibição parcial do <caminho do arquivo de exibição parcial compartilhada>. 19/11/1863 12:00:00 AM

A segunda exibição parcial renderiza as seções do artigo:

Índice da seção um: 0

Pontuação de quatro e há sete anos...

Índice da seção dois: 1

Agora estamos envolvidos em uma grande guerra civil, testando...

Índice da seção três: 2

Mas, em um sentido mais amplo, não podemos dedicar...

Recursos adicionais