Nota
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare ad accedere o a cambiare directory.
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare a cambiare directory.
Annotazioni
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
Avvertimento
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
Blazor Gli pwa possono ricevere e visualizzare notifiche push (messaggi di dati) da un server back-end, anche quando l'utente non usa attivamente l'app. Ad esempio, le notifiche push possono essere inviate quando un utente diverso esegue un'azione nel pwa installato o quando l'app o gli utenti che interagiscono direttamente con l'app del server back-end eseguono un'azione.
Usare le notifiche push per:
- Notificare agli utenti che è successo qualcosa di importante, richiedendo loro di tornare all'app.
- Aggiornare i dati archiviati nell'app, ad esempio un feed di notizie, in modo che l'utente disponga di dati aggiornati al ritorno successivo all'app, anche se sono offline quando viene eseguita la notifica push.
I meccanismi per l'invio, la ricezione e la visualizzazione di una notifica push sono indipendenti da Blazor WebAssembly. L'invio di una notifica push viene implementato dal server back-end, che può usare qualsiasi tecnologia. La ricezione e la visualizzazione di una notifica push sul client sono implementate nel file JavaScript del service worker (JS).
L'esempio in questo articolo usa le notifiche push per fornire aggiornamenti dello stato degli ordini ai clienti di un ristorante pizza basato sull'app dimostrativa Blazing Pizza Workshop PWA. Non è necessario partecipare al workshop online per usare questo articolo, ma il workshop è un'introduzione utile allo Blazor sviluppo di PWA.
Annotazioni
L'app Blazing Pizza adotta il modello di repository per creare un livello di astrazione tra il livello dell'interfaccia utente e il livello di accesso ai dati. Per altre informazioni, vedere Modello UoW (Unit of Work) e Progettazione del livello di persistenza dell'infrastruttura.
Stabilire chiavi pubbliche e private
Generare le chiavi pubbliche e private di crittografia per proteggere le notifiche push in locale, ad esempio con PowerShell o IIS o usando uno strumento online.
Segnaposto usato nel codice di esempio di questo articolo:
-
{PUBLIC KEY}: chiave pubblica. -
{PRIVATE KEY}: chiave privata.
Per gli esempi C# di questo articolo, aggiornare l'indirizzo someone@example.com di posta elettronica in modo che corrisponda all'indirizzo usato durante la creazione della coppia di chiavi personalizzata.
Quando si implementano le notifiche push, assicurarsi che le chiavi crittografiche vengano gestite in modo sicuro:
- Generazione di chiavi: usare una libreria o uno strumento attendibile per generare le chiavi pubbliche e private. Evitare di usare algoritmi deboli o obsoleti.
- Archiviazione delle chiavi: archiviare le chiavi private in modo sicuro nel server, usando un meccanismo di archiviazione sicura, ad esempio un modulo di protezione hardware (HSM) o una risorsa di archiviazione crittografata. Non esporre mai chiavi private al client.
- Utilizzo delle chiavi: usare la chiave privata solo per la firma dei payload delle notifiche push. Assicurarsi che la chiave pubblica sia distribuita in modo sicuro ai client.
Per altre informazioni sulle procedure consigliate per la crittografia, vedere Servizi di crittografia.
Creare una sottoscrizione
Prima di inviare notifiche push a un utente, l'app deve chiedere all'utente l'autorizzazione. Se concedono l'autorizzazione per ricevere notifiche, il browser genera una sottoscrizione, che include un set di token che l'app può usare per instradare le notifiche all'utente.
L'autorizzazione può essere ottenuta in qualsiasi momento dall'app, ma è consigliabile chiedere solo agli utenti l'autorizzazione quando è chiaro perché vogliono sottoscrivere le notifiche dall'app. L'esempio seguente chiede agli utenti quando arrivano nella pagina di checkout (Checkout componente) perché a quel punto è chiaro che l'utente è serio per effettuare un ordine.
Se l'utente accetta di ricevere notifiche, l'esempio seguente invia i dati della sottoscrizione di notifica push al server, in cui i token di notifica push vengono archiviati nel database per un uso successivo.
Aggiungere un file di notifiche JS push per richiedere una sottoscrizione:
- Chiamare
navigator.serviceWorker.getRegistrationper ottenere la registrazione del service worker. - Chiamare
worker.pushManager.getSubscriptionper determinare se esiste una sottoscrizione. - Se non esiste una sottoscrizione, creare una nuova sottoscrizione usando la
PushManager.subscribefunzione e restituire l'URL e i token della nuova sottoscrizione.
Nell'app Blazing Pizza il JS file è denominato pushNotifications.js e si trova nella cartella public static assets (wwwroot) del progetto di libreria di classi della Razor soluzione (BlazingPizza.ComponentsLibrary). La blazorPushNotifications.requestSubscription funzione richiede una sottoscrizione.
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);
}
})();
Annotazioni
Per altre informazioni sulla funzione precedente arrayBufferToBase64 , vedere Come è possibile convertire arrayBuffer in una stringa con codifica base64? (Stack Overflow).
Sul server vengono creati un oggetto di sottoscrizione e un endpoint di notifica per sottoscrizione. L'endpoint riceve chiamate API Web client con dati di sottoscrizione di notifica push, inclusi i token crittografici. I dati vengono archiviati nel database per ogni utente dell'app.
Nell'app Blazing Pizza, l'oggetto abbonamento è la classe NotificationSubscription. Le P256dh proprietà e Auth sono token crittografici dell'utente.
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; }
}
L'endpoint notifications/subscribe viene definito nel metodo di estensione dell'app MapPizzaApi , chiamato nel file dell'app Program per configurare gli endpoint API Web per l'app. La sottoscrizione di notifica dell'utente (NotificationSubscription), che include i token di notifica push, viene archiviata nel database. Viene archiviata una sola sottoscrizione per utente. In alternativa, è possibile consentire all'utente di registrare più sottoscrizioni da browser o dispositivi diversi.
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);
});
In BlazingPizza.Client/HttpRepository.cs il metodo SubscribeToNotifications emette un'operazione HTTP PUT all'endpoint delle sottoscrizioni sul server.
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();
}
}
L'interfaccia del repository (BlazingPizza.Shared/IRepository.cs) include la firma del metodo di SubscribeToNotifications:
public interface IRepository
{
...
Task SubscribeToNotifications(NotificationSubscription subscription);
}
Definire un metodo per richiedere una sottoscrizione e sottoscrivere le notifiche se viene stabilita la sottoscrizione. Salvare la sottoscrizione nel database per usarla in un secondo momento.
Checkout Nel componente dell'app Blazing Pizza il RequestNotificationSubscriptionAsync metodo esegue i compiti seguenti:
- La sottoscrizione viene creata tramite JS interop chiamando
blazorPushNotifications.requestSubscription. Il componente inserisce il IJSRuntime servizio per richiamare la JS funzione. - Il
SubscribeToNotificationsmetodo viene chiamato per salvare la sottoscrizione.
In 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();
}
}
}
Nel componente Checkout, RequestNotificationSubscriptionAsync viene chiamato nel metodo del ciclo di vita OnInitialized ed eseguito all'inizializzazione del componente. Il metodo è asincrono, ma può essere eseguito in background e l'oggetto Task restituito può essere rimosso. Di conseguenza, il metodo non viene chiamato nel metodo del ciclo di vita asincrono per l'inizializzazione dei componenti (OnInitializedAsync). Questo approccio rende più veloce il componente.
protected override void OnInitialized()
{
_ = RequestNotificationSubscriptionAsync();
}
Per illustrare il funzionamento del codice, eseguire l'app Blazing Pizza e iniziare a effettuare un ordine. Passare alla schermata di checkout per visualizzare la richiesta di abbonamento.
Scegliere Consenti e controllare la presenza di errori nella console degli strumenti di sviluppo del browser. È possibile impostare un punto di interruzione nel codice di PizzaApiExtensions e eseguire l'app in modalità debug per esaminare i dati in arrivo dal browser. I dati includono un URL dell'endpoint e i token di crittografia.
Dopo che l'utente ha consentito o bloccato le notifiche per un determinato sito, il browser non chiederà di nuovo. Per reimpostare l'autorizzazione per ulteriori test per Google Chrome o Microsoft Edge, selezionare l'icona "informazioni" (🛈) a sinistra della barra degli indirizzi del browser e modificare Notifiche su Chiedi (impostazione predefinita), come illustrato nell'immagine seguente:
Selezionando "Chiedi (impostazione predefinita)" per "Notifiche" nell'app, le notifiche verranno reimpostate allo stato disabilitato.
Inviare una notifica
L'invio di una notifica comporta l'esecuzione di alcune operazioni di crittografia complesse sul server per proteggere i dati in transito. La maggior parte della complessità viene gestita per l'app da un pacchetto NuGet di terze parti, , WebPushche viene usato dal progetto server (BlazingPizza.Server) nell'app Blazing Pizza.
Il SendNotificationAsync metodo invia le notifiche degli ordini usando la sottoscrizione acquisita. Il codice seguente usa le WebPush API per l'invio della notifica. Il payload della notifica è json serializzato e include un messaggio e un URL. Il messaggio viene visualizzato all'utente e l'URL consente all'utente di raggiungere l'ordine di pizza associato alla notifica. È possibile serializzare parametri aggiuntivi in base alle esigenze per altri scenari di notifica.
Attenzione
Nell'esempio seguente è consigliabile usare un approccio sicuro per fornire la chiave privata. Quando si lavora localmente nell'ambiente Development , è possibile fornire all'app una chiave privata usando lo strumento Secret Manager . In Development, Staging e Production ambienti, è possibile usare Azure Key Vault con identità gestite di Azure. È importante notare che per ottenere la chiave privata di un certificato da un insieme di credenziali di chiavi, il certificato deve avere una chiave privata esportabile.
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}");
}
}
L'esempio precedente consente al server di inviare notifiche, ma il browser non reagisce alle notifiche senza logica aggiuntiva. La visualizzazione delle notifiche è illustrata nella sezione Visualizzare le notifiche .
La console degli strumenti di sviluppo del browser indica l'arrivo delle notifiche dieci secondi dopo che gli ordini vengono inseriti nell'app Blazing Pizza. Nella scheda Applicazione aprire la sezione Messaggistica push . Selezionare il cerchio per avviare la registrazione:
Visualizzare le notifiche
Il service worker della PWA (service-worker.js) deve gestire le notifiche push affinché l'app le visualizzi.
Il push gestore eventi seguente nell'applicazione Blazing Pizza chiama showNotification per creare una notifica per il service worker attivo.
In 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 }
})
);
});
Il codice precedente non diventa effettivo fino al caricamento della pagina successiva quando il browser registra Installing service worker.... Quando si fatica ad aggiornare il service worker, usare la scheda Applicazione nella console degli strumenti di sviluppo del browser. In Service Worker, scegliere Aggiorna o usare Deregistra per forzare una nuova registrazione al caricamento successivo.
Con il codice precedente e un nuovo ordine effettuato da un utente, l'ordine passa allo stato di In consegna dopo 10 secondi in base al meccanismo dimostrativo integrato dell'app. Il browser riceve una notifica push:
Quando si usa l'app in Google Chrome o Microsoft Edge, la notifica viene visualizzata anche se l'utente non usa attivamente l'app Blazing Pizza. Tuttavia, il browser deve essere in esecuzione oppure la notifica viene visualizzata alla successiva apertura del browser.
Quando si usa pwa installato, la notifica deve essere recapitata anche se l'utente non esegue l'app.
Gestire i clic di notifica
Registrare un notificationclick gestore eventi per elaborare l'azione di un utente quando seleziona (fa clic su) una notifica push sul dispositivo:
- Chiudere la notifica chiamando
event.notification.close. - Chiamare
clients.openWindowper creare un nuovo contesto di esplorazione di primo livello e caricare l'URL passato al metodo .
L'esempio seguente nell'app Blazing Pizza porta l'utente alla pagina di stato dell'ordine per l'ordine relativo alla notifica. L'URL viene fornito dal event.notification.data.url parametro , che viene inviato dal server nel payload della notifica.
Nel file del service worker (service-worker.js):
self.addEventListener('notificationclick', event => {
event.notification.close();
event.waitUntil(clients.openWindow(event.notification.data.url));
});
Se il PWA è installato nel dispositivo, il pwa viene visualizzato nel dispositivo. Se il PWA non è installato, l'utente viene indirizzato alla pagina dell'app nel browser.