Eventos
Campeonato Mundial de Visualização de Dados do Power BI
14 de fev., 16 - 31 de mar., 16
Com 4 chances de participar, você pode ganhar um pacote de conferência e chegar à Grande Final AO VIVO em Las Vegas
Saiba maisNão há mais suporte para esse navegador.
Atualize o Microsoft Edge para aproveitar os recursos, o suporte técnico e as atualizações de segurança mais recentes.
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte a Política de Suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 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 a versão atual, consulte a versão .NET 9 deste artigo.
Esse artigo explica como hospedar e implantar aplicativos Blazor (Blazor Web Apps e Blazor Servers) do lado do servidor usando o ASP.NET Core.
Os aplicativos Blazor do lado do servidor podem aceitar valores de configuração de Host Genérico.
Ao usar um modelo de hospedagem no lado do servidor, Blazor é executado no servidor a partir de um aplicativo do ASP.NET Core. As atualizações da interface do usuário, a manipulação de eventos e as chamadas de JavaScript são realizadas por uma conexão SignalR.
É necessário um servidor Web capaz de hospedar um aplicativo ASP.NET Core. O Visual Studio inclui um modelo de projeto de aplicativo do lado do servidor. Para obter mais informações sobre modelos de projeto Blazor, consulte Estrutura do projeto Blazor do ASP.NET Core.
Publique um aplicativo na configuração de versão e implante o conteúdo da pasta bin/Release/{TARGET FRAMEWORK}/publish
, em que o espaço reservado {TARGET FRAMEWORK}
é a estrutura de destino.
Ao considerar a escalabilidade de um único servidor (escalar verticalmente), a memória disponível para um aplicativo provavelmente é o primeiro recurso que o aplicativo esgota à medida que as demandas do usuário aumentam. A memória disponível no servidor afeta:
Para obter diretrizes sobre como compilar aplicativos Blazor seguros e escalonáveis do lado do servidor, consulte os recursos a seguir:
Cada circuito usa aproximadamente 250 KB de memória para um aplicativo mínimo de estilo Olá, Mundo. O tamanho de um circuito depende do código do aplicativo e dos requisitos de manutenção de estado associados a cada componente. Recomendamos que você meça as demandas de recursos durante o desenvolvimento para seu aplicativo e infraestrutura, mas a linha de base a seguir pode ser um ponto de partida no planejamento de seu destino de implantação: se você espera que seu aplicativo dê suporte a 5.000 usuários simultâneos, considere o orçamento de pelo menos 1,3 GB de memória do servidor para o aplicativo (ou ~273 KB por usuário).
As condições de hospedagem e dimensionamento do SignalR se aplicam aos aplicativos Blazor que usam SignalR.
Para obter mais informações sobre aplicativos SignalR em Blazor, incluindo diretrizes de configuração, consulte ASP.NET Core BlazorSignalR diretrizes.
Blazor funciona melhor ao usar WebSockets como o transporte do SignalR devido à menor latência, melhor confiabilidade e maior segurança. A Sondagem Longa é usada por SignalR quando WebSockets não está disponível ou quando o aplicativo está explicitamente configurado para usar a Sondagem Longa.
Um aviso do console será exibido se a Sondagem Longa for utilizada:
Falha ao se conectar por meio de WebSockets usando o transporte de fallback de Sondagem Longa. Isso pode ocorrer porque uma VPN ou proxy está bloqueando a conexão.
Recomendações para implantações globais nos data centers geográficos:
Para hospedar um Serviço de Aplicativo do Azure, é necessário configurar WebSockets e afinidade de sessão, também chamada de afinidade ARR (Application Request Routing).
Observação
Um aplicativo Blazor no Serviço de Aplicativo do Azure não requer o Serviço SignalR do Azure.
Para o registro do aplicativo no Serviço de Aplicativo do Azure, habilite:
O Serviço SignalR do Azure funciona em conjunto com o hub SignalR do aplicativo para escalar verticalmente um aplicativo do lado do servidor para um grande número de conexões simultâneas. Além disso, o alcance global do serviço e os data centers de alto desempenho ajudam significativamente a reduzir a latência devido à geografia.
O serviço não é necessário para aplicativos Blazor hospedados no Serviço de Aplicativo do Azure ou nos Aplicativos de Contêiner do Azure, mas pode ser útil em outros ambientes de hospedagem:
O Serviço do SignalR Azure com o SDK v1.26.1 ou posterior dá suporte a SignalR reconexão com estado (WithStatefulReconnect).
Caso o aplicativo use a Sondagem longa ou retorne para Songadem Londa em vez de WebSockets, talvez seja necessário configurar o intervalo máximo de sondagem (MaxPollIntervalInSeconds
, padrão: 5 segundos, limite: 1-300 segundos), que define o intervalo máximo de sondagem permitido para conexões de Sondagem longa no Serviço SignalR do Azure. Se a próxima solicitação de sondagem não chegar dentro do intervalo máximo de sondagem, o serviço fechará a conexão do cliente.
Para obter diretrizes sobre como adicionar o serviço como uma dependência a uma implantação de produção, consulte Publicar um aplicativo SignalR do ASP.NET Core no Serviço de Aplicativo do Azure.
Para saber mais, veja:
Para ver uma exploração mais detalhada da escala de aplicativos Blazor do lado do servidor no serviço Aplicativos de Contêiner do Azure, confira Como escalar aplicativos ASP.NET Core no Azure. O tutorial explica como criar e integrar os serviços necessários para hospedar aplicativos nos Aplicativos de Contêiner do Azure. As etapas básicas também são fornecidas nesta seção.
Configure o serviço Aplicativos de Contêiner do Azure para a afinidade de sessão seguindo as diretrizes descritas em Afinidade de sessão nos Aplicativos de Contêiner do Azure (documentação do Azure).
O serviço de DP (Proteção de Dados) do ASP.NET Core precisa ser configurado para manter as chaves em uma localização centralizada que todas as instâncias de contêiner podem acessar. As chaves podem ser armazenadas no Armazenamento de Blobs do Azure e protegidas com o Azure Key Vault. O serviço de DP usa as chaves para desserializar componentes Razor. Para configurar o serviço de DP para usar o Armazenamento de Blobs do Azure e o Azure Key Vault, faça referência aos seguintes pacotes NuGet:
Azure.Identity
: fornece classes para trabalhar com os serviços de gerenciamento de acesso e identidade do Azure.Microsoft.Extensions.Azure
: fornece métodos de extensão úteis para executar as principais configurações do Azure.Azure.Extensions.AspNetCore.DataProtection.Blobs
: permite armazenar chaves de Proteção de Dados ASP.NET Core no Armazenamento de Blobs do Azure para que as chaves possam ser compartilhadas entre várias instâncias de um aplicativo Web.Azure.Extensions.AspNetCore.DataProtection.Keys
: habilita a proteção de chaves em repouso usando o recurso de Criptografia/Encapsulamento de Chaves do Azure Key Vault.Observação
Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.
Atualize Program.cs
com o seguinte código realçado:
using Azure.Identity;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Azure;
var builder = WebApplication.CreateBuilder(args);
var BlobStorageUri = builder.Configuration["AzureURIs:BlobStorage"];
var KeyVaultURI = builder.Configuration["AzureURIs:KeyVault"];
builder.Services.AddRazorPages();
builder.Services.AddHttpClient();
builder.Services.AddServerSideBlazor();
builder.Services.AddAzureClientsCore();
builder.Services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri(BlobStorageUri),
new DefaultAzureCredential())
.ProtectKeysWithAzureKeyVault(new Uri(KeyVaultURI),
new DefaultAzureCredential());
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
As alterações anteriores permitem que o aplicativo gerencie o serviço de DP usando uma arquitetura centralizada e escalonável. DefaultAzureCredential descobre a identidade gerenciada do aplicativo de contêiner depois que o código é implantado no Azure e o usa para se conectar ao armazenamento de blobs e ao cofre de chaves do aplicativo.
Para criar a identidade gerenciada do aplicativo de contêiner e conceder-lhe acesso ao armazenamento de blobs e a um cofre de chaves, conclua as seguintes etapas:
scalablerazorstorage
.Repita as configurações anteriores para o cofre de chaves. Selecione o serviço e a chave do cofre de chaves apropriados na guia Básico.
Ao usar o IIS, habilite:
Para obter mais informações, consulte as diretrizes e links cruzados de recursos externos do IIS em Publicar um aplicativo do ASP.NET Core no IIS.
Crie uma definição de entrada com as seguintes Anotações do Kubernetes para afinidade de sessão:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: <ingress-name>
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "affinity"
nginx.ingress.kubernetes.io/session-cookie-expires: "14400"
nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"
Siga as diretrizes para um aplicativo SignalR do ASP.NET Core com as seguintes alterações:
location
caminho de /hubroute
(location /hubroute { ... }
) para o caminho raiz /
(location / { ... }
).proxy_buffering off;
), pois a configuração só se aplica a SSE (Eventos Enviados pelo Servidor), que não são relevantes para as interações cliente-servidor do aplicativo do Blazor.Para obter mais informações e diretrizes de configuração, confira os seguintes recursos:
Para hospedar um aplicativo Blazor por trás do Apache no Linux, configure ProxyPass
para tráfego HTTP e WebSockets.
No exemplo a seguir:
ProxyPreserveHost On
ProxyPassMatch ^/_blazor/(.*) http://localhost:5000/_blazor/$1
ProxyPass /_blazor ws://localhost:5000/_blazor
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
Habilite os seguintes módulos:
a2enmod proxy
a2enmod proxy_wstunnel
Verifique se há erros de WebSockets no console do navegador. Erros de exemplo:
Para obter mais informações e diretrizes de configuração, confira os seguintes recursos:
JSO interoperabilidade pode ser usado para medir a latência de rede, como demonstra o exemplo a seguir.
MeasureLatency.razor
:
@inject IJSRuntime JS
<h2>Measure Latency</h2>
@if (latency is null)
{
<span>Calculating...</span>
}
else
{
<span>@(latency.Value.TotalMilliseconds)ms</span>
}
@code {
private DateTime startTime;
private TimeSpan? latency;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
startTime = DateTime.UtcNow;
var _ = await JS.InvokeAsync<string>("toString");
latency = DateTime.UtcNow - startTime;
StateHasChanged();
}
}
}
@inject IJSRuntime JS
<h2>Measure Latency</h2>
@if (latency is null)
{
<span>Calculating...</span>
}
else
{
<span>@(latency.Value.TotalMilliseconds)ms</span>
}
@code {
private DateTime startTime;
private TimeSpan? latency;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
startTime = DateTime.UtcNow;
var _ = await JS.InvokeAsync<string>("toString");
latency = DateTime.UtcNow - startTime;
StateHasChanged();
}
}
}
@inject IJSRuntime JS
<h2>Measure Latency</h2>
@if (latency is null)
{
<span>Calculating...</span>
}
else
{
<span>@(latency.Value.TotalMilliseconds)ms</span>
}
@code {
private DateTime startTime;
private TimeSpan? latency;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
startTime = DateTime.UtcNow;
var _ = await JS.InvokeAsync<string>("toString");
latency = DateTime.UtcNow - startTime;
StateHasChanged();
}
}
}
@inject IJSRuntime JS
<h2>Measure Latency</h2>
@if (latency is null)
{
<span>Calculating...</span>
}
else
{
<span>@(latency.Value.TotalMilliseconds)ms</span>
}
@code {
private DateTime startTime;
private TimeSpan? latency;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
startTime = DateTime.UtcNow;
var _ = await JS.InvokeAsync<string>("toString");
latency = DateTime.UtcNow - startTime;
StateHasChanged();
}
}
}
@inject IJSRuntime JS
@if (latency is null)
{
<span>Calculating...</span>
}
else
{
<span>@(latency.Value.TotalMilliseconds)ms</span>
}
@code {
private DateTime startTime;
private TimeSpan? latency;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
startTime = DateTime.UtcNow;
var _ = await JS.InvokeAsync<string>("toString");
latency = DateTime.UtcNow - startTime;
StateHasChanged();
}
}
}
Para uma experiência de interface do usuário razoável, recomendamos uma latência de interface do usuário sustentada de 250 ms ou menos.
No servidor, um novo circuito é criado para cada sessão de usuário. Cada sessão de usuário corresponde à renderização de um único documento no navegador. Por exemplo, várias guias criam várias sessões.
Blazor mantém uma conexão constante com o navegador, chamado de circuito, que iniciou a sessão. As conexões podem ser perdidas a qualquer momento por vários motivos, como quando o usuário perde a conectividade de rede ou fecha abruptamente o navegador. Quando uma conexão é perdida, Blazor tem um mecanismo de recuperação que coloca um número limitado de circuitos em um pool "desconectado", dando aos clientes uma quantidade limitada de tempo para reconectar e restabelecer a sessão (padrão: 3 minutos).
Depois desse tempo, Blazor libera o circuito e descarta a sessão. Desse ponto em diante, o circuito é qualificado para GC (coleta de lixo) e é reivindicado quando uma coleta para a geração de GC do circuito é disparada. Um aspecto importante a ser compreendido é que os circuitos têm um longo tempo de vida, o que significa que a maioria dos objetos com raiz pelo circuito eventualmente chega à Gen 2. Como resultado, talvez você não veja esses objetos liberados até que ocorra uma coleção Gen 2.
Pré-requisitos:
Calculamos a memória usada pelo blazor da seguinte maneira:
(Circuitos ativos × memória por circuito) + (Circuitos desconectados × Memória por circuito)
A quantidade de memória que um circuito usa e os circuitos ativos potenciais máximos que um aplicativo pode manter dependem em grande parte de como o aplicativo é gravado. O número máximo de circuitos ativos possíveis é descrito aproximadamente por:
Máximo de memória disponível / Memória pré-circuito = Máximo de circuitos ativos potenciais
Para que ocorra um vazamento de memória no Blazor, o seguinte deve ser verdadeiro:
Em outros casos, não há perda de memória. Se o circuito estiver ativo (conectado ou desconectado), o circuito ainda estará em uso.
Se uma coleção para a geração de GC do circuito não for executada, a memória não será liberada porque o coletor de lixo não precisará liberar a memória nesse momento.
Se uma coleção de uma geração de GC for executada e liberar o circuito, você deverá validar a memória em relação às estatísticas do GC, não ao processo, pois o .NET pode decidir manter a memória virtual ativa.
Se a memória não for liberada, você deverá encontrar um circuito que não esteja ativo ou desconectado e com raiz por outro objeto na estrutura. Em qualquer outro caso, a incapacidade de liberar memória é um problema de aplicativo no código do desenvolvedor.
Adote qualquer uma das seguintes estratégias para reduzir o uso de memória de um aplicativo:
Ao criar um Blazor aplicativo que é executado no cliente e direcionado a navegadores de dispositivos móveis, especialmente Safari no iOS, pode ser necessário diminuir a memória máxima do aplicativo com a propriedade MSBuild EmccMaximumHeapSize
. Para obter mais informações, confira Hospedar e implantar Blazor WebAssembly do ASP.NET Core.
dotnet-counters
. Para obter mais informações, consulte Investigar contadores de desempenho (dotnet-counters).dotnet-counters
, pois verá os GCs acontecerem e a quantidade de memória usada cair para 0 (zero), mas não verá o contador do conjunto de trabalho diminuir, o que é um sinal de que o .NET está mantendo a memória para reutilizá-la. Para obter mais informações sobre as configurações do arquivo de projeto (.csproj
) para controlar esse comportamento, consulte Opções de configuração de runtime para coleta de lixo.GC.Collect(2, GCCollectionMode.Aggressive | GCCollectionMode.Forced, blocking: true, compacting: true))
) libera a memória?Comentários do ASP.NET Core
O ASP.NET Core é um projeto código aberto. Selecione um link para fornecer comentários:
Eventos
Campeonato Mundial de Visualização de Dados do Power BI
14 de fev., 16 - 31 de mar., 16
Com 4 chances de participar, você pode ganhar um pacote de conferência e chegar à Grande Final AO VIVO em Las Vegas
Saiba maisTreinamento
Roteiro de aprendizagem
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization