Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión de .NET 9 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la política de soporte de .NET y .NET Core. Para la versión actual, consulte la versión de .NET 9 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no ofrece ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión de .NET 9 de este artículo.
En este artículo se explica cómo hospedar e implementar aplicaciones Blazor del lado del servidor (aplicaciones Blazor Web App y Blazor Server) mediante ASP.NET Core.
Valores de configuración de host
Las aplicaciones del lado del servidorBlazor pueden aceptarvalores de configuración de host genérico.
Despliegue
Mediante un modelo de hospedaje del lado del servidor Blazor se ejecuta en el servidor desde una aplicación ASP.NET Core. Las actualizaciones de la interfaz de usuario, el control de eventos y las llamadas de JavaScript se controlan mediante una conexión SignalR.
Se requiere un servidor web que pueda hospedar una aplicación ASP.NET Core. Visual Studio incluye una plantilla de proyecto de aplicación del lado del servidor. Para más información sobre las plantillas de proyecto de Blazor, vea Estructura del proyecto de Blazor de ASP.NET Core.
Publique una aplicación en la configuración de versión e implemente el contenido de la carpeta bin/Release/{TARGET FRAMEWORK}/publish
, donde el marcador de posición {TARGET FRAMEWORK}
es la plataforma de destino.
Escalabilidad
A la hora de considerar la escalabilidad de un solo servidor (escalado vertical), la memoria disponible para una aplicación es probablemente el primer recurso que la aplicación agota a medida que la demanda de los usuarios aumenta. La memoria disponible en el servidor afecta a lo siguiente:
- Número de circuitos activos que un servidor puede admitir.
- Latencia de la interfaz de usuario en el cliente.
Para obtener instrucciones sobre la creación de aplicaciones del lado servidor seguras y escalables de Blazor, consulte los siguientes recursos:
- Guía de mitigación de amenazas para ASP.NET Core Blazor representación estática del lado servidor
- Guía de mitigación de amenazas para ASP.NET Core Blazor representación interactiva del lado servidor
Cada circuito utiliza aproximadamente 250 KB de memoria para una aplicación mínima de estilo Hola mundo. El tamaño de un circuito depende del código de la aplicación y de los requisitos de mantenimiento del estado asociados a cada componente. Se recomienda que mida la demanda de recursos durante el desarrollo de la aplicación y la infraestructura, pero la línea de base siguiente puede ser un punto de partida para planear el destino de implementación: Si espera que la aplicación admita 5000 usuarios simultáneos, considere la posibilidad de presupuestar al menos 1,3 GB de memoria del servidor en la aplicación (o ~273 KB por usuario).
Configuración de SignalR
SignalR Las condiciones de hospedaje y escalado de se aplican a aplicaciones Blazor que usan SignalR.
Para obtener más información sobre las aplicaciones de SignalR enBlazor, incluida la guía de configuración, consulte la Guía deBlazorSignalR ASP.NET Core.
Transportes
Blazor funciona mejor cuando se usa WebSockets como transporte de SignalR debido a su menor latencia, su mayor confiabilidad y su seguridad mejorada. SignalR usa el sondeo largo cuando WebSockets no está disponible o cuando la aplicación está configurada explícitamente para usarlo.
Aparece una advertencia en la consola si se utiliza el sondeo largo:
No se pudo conectar a través de WebSockets mediante el transporte de reserva de sondeo largo. Esto puede deberse a que una VPN o un proxy bloquean la conexión.
Errores de implementación global y conexión
Recomendaciones para implementaciones globales en centros de datos geográficos:
- Implemente la aplicación en las regiones donde residen la mayoría de los usuarios.
- Tenga en cuenta la mayor latencia para el tráfico entre continentes. Para controlar la apariencia de la interfaz de usuario de reconexión, vea ASP.NET Core BlazorSignalR guía.
- Considere el uso de Azure SignalR Service.
Azure App Service
El hosting en Azure App Service requiere la configuración de WebSockets y la afinidad de sesión, también conocida como afinidad ARR (Application Request Routing).
Nota:
Una aplicación Blazor en Azure App Service no requiere Azure SignalR Service.
Habilite lo siguiente para el registro de la aplicación en Azure App Service:
- WebSockets para permitir que funcione el transporte WebSockets. El valor predeterminado es Desactivado.
- Afinidad de sesión para enrutar las solicitudes de un usuario a la misma instancia del servicio de aplicaciones (App Service). El valor predeterminado es Activado.
- En Azure Portal, vaya a la aplicación web en App Services.
- Abra Ajustes>Configuración.
- Establezca sockets Web en Activado.
- Compruebe que Session affinity está establecido en Activado.
Azure SignalR Service
El Servicio opcional SignalR de Azure funciona junto con el SignalR centro de la aplicación para escalar una aplicación del lado del servidor a un gran número de conexiones simultáneas. Además, los centros de datos de alto rendimiento y alcance global del servicio son de gran ayuda a la hora de reducir la latencia ocasionada por la geografía.
El servicio no es necesario para aplicaciones Blazor hospedadas en Azure App Service o Azure Container Apps, pero puede ser útil en otros entornos de hospedamiento:
- Para facilitar la escalabilidad horizontal de la conexión.
- Gestionar la distribución global.
El servicio Azure SignalR con el SDK v1.26.1 o posterior admite SignalR reconexión con estado (WithStatefulReconnect).
En caso de que la aplicación utilice Long Polling o vuelva a Long Polling en lugar de WebSockets, es posible que deba configurar el intervalo de sondeo máximo (MaxPollIntervalInSeconds
, predeterminado: 5 segundos, límite: 1-300 segundos), que define el intervalo de sondeo máximo permitido para las conexiones de Long Polling en el Azure SignalR Service. Si la siguiente solicitud de sondeo no llega dentro del intervalo de sondeo máximo, el servicio cierra la conexión del cliente.
Para obtener orientación sobre cómo agregar el servicio como dependencia a una implementación de producción, consulte Publicar una aplicación ASP.NET Core SignalR en Azure App Service.
Para obtener más información, consulte:
- Azure SignalR Service
- ¿Qué es Azure SignalR Service?
- Hospedaje y escalado de producción de ASP.NET Core SignalR
- Publicar una aplicación ASP.NET Core SignalR para Azure App Service
Azure Container Apps (Aplicaciones de Contenedores de Azure)
Para una exploración más profunda del escalado de aplicaciones del lado servidor Blazor en el servicio Azure Container Apps, consulte Escalado de aplicaciones de ASP.NET Core en Azure. En el tutorial se explica cómo crear e integrar los servicios necesarios para hospedar aplicaciones en Azure Container Apps. Los pasos básicos también se proporcionan en esta sección.
Configure el servicio Azure Container Apps para la afinidad de sesión siguiendo las instrucciones de Afinidad de sesión en Azure Container Apps (documentación de Azure).
El servicio ASP.NET Core Data Protection (DP) debe configurarse para mantener las claves en una ubicación centralizada a la que puedan acceder todas las instancias de contenedor. Las claves se pueden almacenar en Azure Blob Storage y protegerse con Azure Key Vault. El servicio DP utiliza las claves para deserializar componentes Razor. Para configurar el servicio DP para utilizar Azure Blob Storage y Azure Key Vault, haga referencia a los siguientes paquetes NuGet:
Azure.Identity
: proporciona clases para trabajar con los servicios de administración de identidades y acceso de Azure.-
Microsoft.Extensions.Azure
: proporciona métodos de extensión útiles para realizar configuraciones básicas de Azure. -
Azure.Extensions.AspNetCore.DataProtection.Blobs
: permite almacenar claves de protección de datos de ASP.NET Core en Azure Blob Storage para poder compartirlas entre varias instancias de una aplicación web. -
Azure.Extensions.AspNetCore.DataProtection.Keys
: habilita la protección de claves en reposo mediante la característica Cifrado y ajuste de claves de Azure Key Vault.
Nota:
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulta los artículos de Instalación y administración de paquetes en Flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
Actualice
Program.cs
con el siguiente código resaltado: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();
Los cambios anteriores permiten a la app administrar el servicio DP utilizando una arquitectura centralizada y escalable. DefaultAzureCredential detecta la identidad administrada de la aplicación contenedora después de implementar el código en Azure y la usa para conectarse a Blob Storage y al almacén de claves de la aplicación.
Para crear la identidad administrada de la aplicación contenedora y concederle acceso a Blob Storage y a un almacén de claves, complete los pasos siguientes:
- En Azure Portal, navegue a la página de información general de la aplicación contenedora.
- Seleccione Conector de servicio en el panel de navegación de la izquierda.
- Seleccione + Crear en el panel de navegación superior.
- En el menú de control flotante Crear conexión, escriba los valores siguientes:
- Contenedor: seleccione la aplicación contenedora que ha creado para hospedar la aplicación.
- Tipo de servicio: seleccione Blob Storage.
- Suscripción: seleccione la suscripción que sea propietaria de la aplicación contenedora.
- Nombre de conexión: escriba un nombre de
scalablerazorstorage
. - Tipo de cliente: seleccione .NET y después Siguiente.
- Seleccione la identidad asignada y gestionada por el sistema y seleccione Siguiente.
- Use la configuración de red predeterminada y seleccione Siguiente.
- Una vez que Azure valide la configuración, seleccione Crear.
Repita la configuración anterior para el almacén de claves. Seleccione el servicio y la clave adecuados del almacén de claves en la pestaña Aspectos básicos.
Nota:
En el ejemplo anterior se usa DefaultAzureCredential para simplificar la autenticación al desarrollar aplicaciones que se implementan en Azure mediante la combinación de credenciales usadas en entornos de hospedaje de Azure con credenciales usadas en el desarrollo local. Al pasar a producción, una alternativa es una mejor opción, como ManagedIdentityCredential. Para más información, consulte Autenticación de aplicaciones .NET hospedadas en Azure en recursos de Azure mediante una identidad administrada asignada por el sistema.
IIS
Al usar IIS, habilite:
Para obtener más información, consulte las instrucciones y los vínculos cruzados de recursos de IIS externos en Publicar una aplicación de ASP.NET Core en IIS.
Kubernetes
Cree una definición de entrada con las siguientes anotaciones de Kubernetes para afinidad de sesión:
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"
Linux con Nginx
Siga las instrucciones para obtener una aplicación SignalR de ASP.NET Core con los siguientes cambios:
- Cambie la ruta de acceso
location
de/hubroute
(location /hubroute { ... }
) a la ruta de acceso/
(location / { ... }
). - Quite la configuración de almacenamiento en búfer de proxy (
proxy_buffering off;
) porque la configuración solo se aplica a los eventos enviados por el servidor (SSE), que no son relevantes para las interacciones cliente-servidor de la aplicación Blazor.
Para obtener más información e instrucciones de configuración, vea los recursos siguientes:
- Hospedaje y escalado de producción de ASP.NET Core SignalR
- Hospedar ASP.NET Core en Linux con Nginx
- Configurar ASP.NET Core para trabajar con servidores proxy y equilibradores de carga
- NGINX como proxy de WebSocket
- Redirección mediante proxy de Websocket
- Consulte a los desarrolladores en foros de soporte técnico que no son de Microsoft:
Linux con Apache
Para hospedar una aplicación de Blazor en Apache en Linux, configure ProxyPass
para el tráfico HTTP y WebSockets.
En el ejemplo siguiente:
- El servidor de Kestrel se está ejecutando en el equipo host.
- La aplicación escucha el tráfico en el puerto 5000.
ProxyPreserveHost On
ProxyPassMatch ^/_blazor/(.*) http://localhost:5000/_blazor/$1
ProxyPass /_blazor ws://localhost:5000/_blazor
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
Habilite los siguientes módulos:
a2enmod proxy
a2enmod proxy_wstunnel
Busque errores de WebSockets en la consola del explorador. Errores de ejemplo:
- Firefox no puede establecer una conexión con el servidor en ws://the-domain-name.tld/_blazor?id=XXX
- Error: No se pudo iniciar el transporte 'WebSockets': Error: Error en el transporte.
- Error: No se pudo iniciar el transporte 'LongPolling': Tipo de error: this.transport no definido
- Error: No se puede conectar con el servidor con ninguno de los transportes disponibles. Error de WebSockets
- Error: No se pueden enviar datos si la conexión no está en estado 'Conectado'.
Para obtener más información e instrucciones de configuración, vea los recursos siguientes:
- Configurar ASP.NET Core para trabajar con servidores proxy y equilibradores de carga
- Documentación de Apache
- Consulte a los desarrolladores en foros de soporte técnico que no son de Microsoft:
Medición de la latencia de red
JS La interoperabilidad de se puede usar para medir la latencia de red, como se muestra en el ejemplo siguiente.
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 una experiencia de interfaz de usuario razonable, se recomienda una latencia de interfaz de usuario sostenida de 250 ms o menos.