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 10 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 10 de este artículo.
Blazor Las PWA pueden recibir y mostrar notificaciones push (mensajes de datos) desde un servidor back-end, incluso cuando el usuario no usa activamente la aplicación. Por ejemplo, las notificaciones push se pueden enviar cuando un usuario diferente realiza una acción en su PWA instalado o cuando la aplicación o los usuarios interactúan directamente con la aplicación de servidor back-end realizan una acción.
Use notificaciones push para:
- Notifique a los usuarios que haya ocurrido algo importante, que les pida que vuelvan a la aplicación.
- Actualice los datos almacenados en la aplicación, como un feed de noticias, para que el usuario tenga datos nuevos en su siguiente retorno a la aplicación, incluso si están sin conexión cuando se emite la notificación push.
Los mecanismos para enviar, recibir y mostrar una notificación push son independientes de Blazor WebAssembly. El servidor back-end implementa el envío de una notificación push, que puede usar cualquier tecnología. La recepción y visualización de una notificación push en el cliente se implementa en el archivo JavaScript del service worker (JS).
En el ejemplo de este artículo se usan notificaciones push para proporcionar actualizaciones de estado de pedido a los clientes de un restaurante de pizzas basado en la aplicación de demostración PWA Blazing Pizza Workshop. No es necesario participar en el taller en línea para usar este artículo, pero el taller es una introducción útil al Blazor desarrollo de PWA.
Nota:
La aplicación Blazing Pizza adopta el patrón de repositorio para crear una capa de abstracción entre la capa de interfaz de usuario y la capa de acceso a datos. Para obtener más información, consulte Patrón de unidad de trabajo (UoW) y Diseñar la capa de persistencia de la infraestructura.
Establecimiento de claves públicas y privadas
Genere las claves criptográficas públicas y privadas para proteger las notificaciones push localmente, por ejemplo con PowerShell o IIS, o mediante una herramienta en línea.
Marcadores de posición usados en el código de ejemplo de este artículo:
-
{PUBLIC KEY}: clave pública. -
{PRIVATE KEY}: clave privada.
En los ejemplos de C# de este artículo, actualice la someone@example.com dirección de correo electrónico para que coincida con la dirección que se usa al crear el par de claves personalizado.
Al implementar notificaciones push, asegúrese de que las claves criptográficas se administran de forma segura:
- Generación de claves: use una biblioteca o herramienta de confianza para generar las claves públicas y privadas. Evite usar algoritmos débiles o obsoletos.
- Almacenamiento de claves: almacene claves privadas de forma segura en el servidor mediante un mecanismo de almacenamiento seguro, como un módulo de seguridad de hardware (HSM) o un almacenamiento cifrado. Nunca exponga claves privadas al cliente.
- Uso de claves: use la clave privada solo para firmar cargas de notificación de inserción. Asegúrese de que la clave pública se distribuye de forma segura a los clientes.
Para obtener más información sobre los procedimientos recomendados criptográficos, consulte Servicios criptográficos.
una suscripción
Antes de enviar notificaciones push a un usuario, la aplicación debe pedir permiso al usuario. Si conceden permiso para recibir notificaciones, su explorador genera una suscripción, que incluye un conjunto de tokens que la aplicación puede usar para enrutar las notificaciones al usuario.
La aplicación puede obtener el permiso en cualquier momento, pero solo se recomienda pedir permiso a los usuarios cuando esté claro por qué quieren suscribirse a las notificaciones de la aplicación. En el ejemplo siguiente se pregunta a los usuarios cuando llegan a la página de pago (Checkout) porque en ese momento está claro que el usuario está realmente interesado en realizar un pedido.
Si el usuario acepta recibir notificaciones, en el ejemplo siguiente se envían los datos de suscripción de notificación push al servidor, donde los tokens de notificación push se almacenan en la base de datos para uso posterior.
Agregue un archivo de notificaciones JS push para solicitar una suscripción:
- Llame a
navigator.serviceWorker.getRegistrationpara obtener el registro del trabajador del servicio. - Llame
worker.pushManager.getSubscriptiona para determinar si existe una suscripción. - Si no existe una suscripción, cree una nueva suscripción mediante la
PushManager.subscribefunción y devuelva la dirección URL y los tokens de la nueva suscripción.
En la aplicación Blazing Pizza, el JS archivo se denomina pushNotifications.js y se encuentra en la carpeta de recursos estáticos públicos (wwwroot) del Razor proyecto de biblioteca de clases de la solución (BlazingPizza.ComponentsLibrary). La blazorPushNotifications.requestSubscription función solicita una suscripción.
BlazingPizza.ComponentsLibrary/wwwroot/pushNotifications.js:
(function () {
const applicationServerPublicKey = '{PUBLIC KEY}';
window.blazorPushNotifications = {
requestSubscription: async () => {
const worker = await navigator.serviceWorker.getRegistration();
const existingSubscription = await worker.pushManager.getSubscription();
if (!existingSubscription) {
const newSubscription = await subscribe(worker);
if (newSubscription) {
return {
url: newSubscription.endpoint,
p256dh: arrayBufferToBase64(newSubscription.getKey('p256dh')),
auth: arrayBufferToBase64(newSubscription.getKey('auth'))
};
}
}
}
};
async function subscribe(worker) {
try {
return await worker.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerPublicKey
});
} catch (error) {
if (error.name === 'NotAllowedError') {
return null;
}
throw error;
}
}
function arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
})();
Nota:
Para obtener más información sobre la función anterior arrayBufferToBase64 , consulte ¿Cómo puedo convertir un objeto ArrayBuffer a una cadena codificada en base64? (Stack Overflow).
Se crea un objeto de suscripción y un punto de conexión de suscripción de notificación en el servidor. El endpoint recibe llamadas de la API web del cliente con datos de suscripción de notificación push, incluidos los tokens criptográficos. Los datos se almacenan en la base de datos para cada usuario de la aplicación.
En la aplicación Blazing Pizza, el objeto de suscripción es la NotificationSubscription clase . Las P256dh propiedades y Auth son los tokens criptográficos del usuario.
BlazingPizza.Shared/NotificationSubscription.cs:
public class NotificationSubscription
{
public int? NotificationSubscriptionId { get; set; }
public string? UserId { get; set; }
public string? Url { get; set; }
public string? P256dh { get; set; }
public string? Auth { get; set; }
}
El punto de conexión notifications/subscribe se define en el método de extensión de la aplicación MapPizzaApi, al que se llama en el archivo Program de la aplicación para configurar puntos de conexión de API web para la aplicación. La suscripción de notificaciones del usuario (NotificationSubscription), que incluye sus tokens de notificaciones push, se almacena en la base de datos. Solo se almacena una suscripción por usuario. Como alternativa, puede permitir que el usuario registre varias suscripciones desde distintos exploradores o dispositivos.
app.MapPut("/notifications/subscribe",
[Authorize] async (
HttpContext context,
PizzaStoreContext db,
NotificationSubscription subscription) =>
{
var userId = GetUserId(context);
if (userId is null)
{
return Results.Unauthorized();
}
// Remove old subscriptions for this user
var oldSubscriptions = db.NotificationSubscriptions.Where(
e => e.UserId == userId);
db.NotificationSubscriptions.RemoveRange(oldSubscriptions);
// Store the new subscription
subscription.UserId = userId;
db.NotificationSubscriptions.Add(subscription);
await db.SaveChangesAsync();
return Results.Ok(subscription);
});
En BlazingPizza.Client/HttpRepository.cs, el método SubscribeToNotifications emite un HTTP PUT al endpoint de suscripciones en el servidor.
public class HttpRepository : IRepository
{
private readonly HttpClient _httpClient;
public HttpRepository(HttpClient httpClient)
{
_httpClient = httpClient;
}
...
public async Task SubscribeToNotifications(NotificationSubscription subscription)
{
var response = await _httpClient.PutAsJsonAsync("notifications/subscribe",
subscription);
response.EnsureSuccessStatusCode();
}
}
La interfaz del repositorio (BlazingPizza.Shared/IRepository.cs) incluye la firma del método de SubscribeToNotifications:
public interface IRepository
{
...
Task SubscribeToNotifications(NotificationSubscription subscription);
}
Defina un método para solicitar una suscripción y suscribirse a las notificaciones si se establece la suscripción. Guarde la suscripción en la base de datos para su uso posterior.
En el Checkout componente de la aplicación Blazing Pizza, el RequestNotificationSubscriptionAsync método realiza las siguientes tareas:
- La suscripción se crea mediante JS interop llamando a
blazorPushNotifications.requestSubscription. El componente inserta el IJSRuntime servicio para invocar la JS función. - El método
SubscribeToNotificationsse llama para guardar la suscripción.
En BlazingPizza.Client/Components/Pages/Checkout.razor:
async Task RequestNotificationSubscriptionAsync()
{
var subscription = await JSRuntime.InvokeAsync<NotificationSubscription>(
"blazorPushNotifications.requestSubscription");
if (subscription is not null)
{
try
{
await Repository.SubscribeToNotifications(subscription);
}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect();
}
}
}
En el componente Checkout, se llama a RequestNotificationSubscriptionAsync en el OnInitializedmétodo de ciclo de vida y se ejecuta en la inicialización del componente. El método es asincrónico, pero se puede ejecutar en segundo plano y el Task que devuelve se puede descartar. Por lo tanto, no se llama al método en el método asincrónico del ciclo de vida para la inicialización de componentes (OnInitializedAsync). Este enfoque hace que el componente sea más rápido.
protected override void OnInitialized()
{
_ = RequestNotificationSubscriptionAsync();
}
Para demostrar cómo funciona el código, ejecute la aplicación Blazing Pizza y empiece a realizar un pedido. Vaya a la pantalla de pago para ver la solicitud de suscripción.
Elija Permitir y compruebe si hay errores en la consola de herramientas de desarrollo del explorador. Puede establecer un punto de interrupción en el código de PizzaApiExtensionsMapPut("/notifications/subscribe"...) y ejecutar la aplicación con depuración para inspeccionar los datos entrantes desde el navegador. Los datos incluyen una dirección URL de punto de conexión y tokens criptográficos.
Después de que el usuario haya permitido o bloqueado las notificaciones de un sitio determinado, el explorador no volverá a preguntar. Para restablecer el permiso para realizar pruebas adicionales para Google Chrome o Microsoft Edge, seleccione el icono "información" (🛈) a la izquierda de la barra de direcciones del explorador y cambie Notificaciones a Preguntar (valor predeterminado), como se muestra en la siguiente imagen:
Envío de una notificación
El envío de una notificación implica realizar algunas operaciones criptográficas complejas en el servidor para proteger los datos en tránsito. La mayor parte de la complejidad de la aplicación la gestiona un paquete NuGet de terceros, WebPush, que utiliza el proyecto de servidor (BlazingPizza.Server) en la aplicación Blazing Pizza.
El SendNotificationAsync método envía notificaciones de pedido mediante la suscripción capturada. El código siguiente usa WebPush las API para enviar la notificación. La carga de la notificación es JSON serializada e incluye un mensaje y una dirección URL. El mensaje se muestra al usuario y la dirección URL permite al usuario llegar al pedido de pizza asociado a la notificación. Se pueden serializar parámetros adicionales según sea necesario para otros escenarios de notificación.
Precaución
En el ejemplo siguiente, se recomienda usar un enfoque seguro para proporcionar la clave privada. Al trabajar localmente en el Development entorno, se puede proporcionar una clave privada a la aplicación mediante la herramienta Administrador de secretos . En los entornos Development, Staging y Production, se puede usar Azure Key Vault con identidades administradas de Azure, teniendo en cuenta que para obtener la clave privada de un certificado de un almacén de claves, el certificado debe contar con una clave privada exportable.
private static async Task SendNotificationAsync(Order order,
NotificationSubscription subscription, string message)
{
var publicKey = "{PUBLIC KEY}";
var privateKey = "{PRIVATE KEY}";
var pushSubscription = new PushSubscription(subscription.Url,
subscription.P256dh, subscription.Auth);
var vapidDetails = new VapidDetails("mailto:<someone@example.com>", publicKey,
privateKey);
var webPushClient = new WebPushClient();
try
{
var payload = JsonSerializer.Serialize(new
{
message,
url = $"myorders/{order.OrderId}",
});
await webPushClient.SendNotificationAsync(pushSubscription, payload,
vapidDetails);
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error sending push notification: {ex.Message}");
}
}
El ejemplo anterior permite al servidor enviar notificaciones, pero el explorador no reacciona a las notificaciones sin lógica adicional. La visualización de notificaciones se trata en la sección Mostrar notificaciones .
La consola de herramientas de desarrollo del explorador indica la llegada de notificaciones diez segundos después de que los pedidos se realizan en la aplicación Blazing Pizza. En la pestaña Aplicación , abra la sección Mensajería push . Seleccione el círculo para Iniciar grabación:
Mostrar notificaciones
El trabajador del servicio de PWA (service-worker.js) debe controlar las notificaciones push para que la aplicación las muestre.
El siguiente push manejador de eventos en la aplicación Blazing Pizza llama showNotification para crear una notificación para el trabajador de servicio activo.
En BlazingPizza/wwwroot/service-worker.js:
self.addEventListener('push', event => {
const payload = event.data.json();
event.waitUntil(
self.registration.showNotification('Blazing Pizza', {
body: payload.message,
icon: 'img/icon-512.png',
vibrate: [100, 50, 100],
data: { url: payload.url }
})
);
});
El código anterior no surte efecto hasta después de cargar la página siguiente cuando el explorador registra Installing service worker.... Cuando tenga dificultades para que el trabajador del servicio se actualice, use la pestaña Aplicación en la consola de herramientas de desarrollo del explorador. En Trabajos de servicio, elija Actualizar o use Anular registro para forzar un nuevo registro en la siguiente carga.
Con el código anterior en su lugar y el nuevo pedido realizado por un usuario, el pedido pasa al estado Out for delivery después de 10 segundos por la lógica de demostración integrada de la aplicación. El explorador recibe una notificación push:
Al usar la aplicación en Google Chrome o Microsoft Edge, la notificación aparece incluso si el usuario no usa activamente la aplicación Blazing Pizza. Sin embargo, el explorador debe estar en ejecución o la notificación aparece la próxima vez que se abra el explorador.
Al usar la PWA instalada, la notificación debe entregarse incluso si el usuario no ejecuta la aplicación.
Controlar clics de notificación
Registre un notificationclick controlador de eventos para procesar la acción de un usuario que selecciona (hace clic) en una notificación push en su dispositivo.
- Cierre la notificación llamando a
event.notification.close. - Llame a
clients.openWindowpara crear un nuevo contexto de navegación de nivel superior y cargar la URL pasada al método.
En el ejemplo siguiente de la aplicación Blazing Pizza se lleva al usuario a la página de estado del pedido para el pedido que pertenece a la notificación. El URL es proporcionado por el parámetro event.notification.data.url, que es enviado por el servidor en la carga de la notificación.
En el archivo de trabajo de servicio (service-worker.js):
self.addEventListener('notificationclick', event => {
event.notification.close();
event.waitUntil(clients.openWindow(event.notification.data.url));
});
Si la PWA está instalada en el dispositivo, la PWA se muestra en el dispositivo. Si la PWA no está instalada, el usuario se lleva a la página de la aplicación en su explorador.