Web Push Notifications in ASP.NET Core

In this post, we’ll walk through how to implement web push notifications in an ASP.NET Core application using Service Workers, Push API, and VAPID for authentication.

Web Push Notifications in ASP.NET Core

Getting Started

Web push notifications are a powerful way to engage users even when they are not actively using your web application. Whether you're sending alerts, reminders, or promotional messages, integrating push notifications into your ASP.NET Core app can greatly enhance user engagement and real-time communication.

Implementing Web Push Notifications

Web Push Notifications allow web apps to send messages to users even when the browser is not active. This is useful for user engagement and timely communication (e.g., reminders, updates, etc.). We'll walk through to implement Web Push Notifications in an ASP.NET Core web application, using:

  • ASP.NET Core for the backend.
  • JavaScript Service Workers for push logic.
  • Web Push libraries to send messages.
  • VAPID for authentication.

Prerequisites
  • Basic understanding of ASP.NET Core (MVC or Razor Pages)
  • .NET 6 or later
  • HTTPS enabled (Push Notifications require a secure context)
  • Browser that supports Push API (Chrome, Firefox, Edge)

Create a new ASP.NET Project
  1. Open Visual Studio
  2. Click "Create a new project"
  3. Search for "ASP.NET Core Web App", then select it and click Next
  4. Name your project and choose a location
  5. Click Next
  6. Choose:
    • .NET version (e.g., .NET 6, 7, or 8)
    • Web App (Model-View-Controller) for MVC or Empty for minimal APIs
    • Uncheck or check HTTPS, Docker, or Authentication as needed
  7. Click Create

Install Required NuGet Packages
Install the Lib.Net.Http.WebPush package, which simplifies push notification creation:
dotnet add package Lib.Net.Http.WebPush

If you want know more about how to install NuGet packages then visit my post "Integrating ChatGPT in ASP.NET Core"

Generate VAPID Keys

VAPID (Voluntary Application Server Identification for Web Push) is used for identifying the server sending the push notification.Use the command-line tool or generate using a library like web-push in Node.js:

You’ll get:
  • Public Key
  • Private Key

Store these safely (in appsettings.json for now).
// appsettings.json
"VapidDetails": {
  "Subject": "mailto:you@example.com",
  "PublicKey": "YourPublicKeyHere",
  "PrivateKey": "YourPrivateKeyHere"
}

Create Push Subscription Model
// Models/PushSubscription.cs
public class PushSubscription
{
  public string Endpoint { get; set; }
  public string P256DH { get; set; }
  public string Auth { get; set; }
}

Create Push Notification Service
 // Services/PushNotificationService.cs  
 using Lib.Net.Http.WebPush;  
 using Lib.Net.Http.WebPush.Authentication;  
 public class PushNotificationService  
 {  
   private readonly VapidDetails _vapidDetails;  
   public PushNotificationService(IConfiguration config)  
   {  
     _vapidDetails = new VapidDetails(  
       config["VapidDetails:Subject"],  
       config["VapidDetails:PublicKey"],  
       config["VapidDetails:PrivateKey"]  
     );  
   }  
   public async Task SendNotification(PushSubscription subscription, string message)  
   {  
     var pushSubscription = new PushSubscription(  
       subscription.Endpoint,  
       subscription.P256DH,  
       subscription.Auth  
     );  
     var client = new PushServiceClient  
     {  
       DefaultAuthentication = _vapidDetails  
     };  
     await client.RequestPushMessageDeliveryAsync(pushSubscription, new PushMessage(message));  
   }  
 }  

Register this in Startup.cs or Program.cs:
builder.Services.AddSingleton<PushNotificationService>();

Create API Endpoint to Receive Subscription
 // Controllers/PushController.cs  
 [ApiController]  
 [Route("api/[controller]")]  
 public class PushController : ControllerBase  
 {  
   private readonly PushNotificationService _pushService;  
   public PushController(PushNotificationService pushService)  
   {  
     _pushService = pushService;  
   }  
   [HttpPost("subscribe")]  
   public IActionResult Subscribe([FromBody] PushSubscription subscription)  
   {  
     // Ideally, store in DB  
     HttpContext.Session.SetString("subscription", JsonSerializer.Serialize(subscription));  
     return Ok();  
   }  
   [HttpPost("send")]  
   public async Task<IActionResult> Send([FromBody] string message)  
   {  
     var subscriptionJson = HttpContext.Session.GetString("subscription");  
     if (string.IsNullOrEmpty(subscriptionJson))  
       return BadRequest("No subscription found.");  
     var subscription = JsonSerializer.Deserialize<PushSubscription>(subscriptionJson);  
     await _pushService.SendNotification(subscription, message);  
     return Ok();  
   }  
 }  

Frontend JavaScript
  1. Add a Service Worker: Create wwwroot/sw.js:
       self.addEventListener('push', function (event) {  
         const data = event.data.text();  
         event.waitUntil(  
           self.registration.showNotification('New Notification', {  
             body: data,  
             icon: '/icon.png'  
           })  
         );  
       });  
      
  2. Register the Service Worker and Subscribe
     <!-- In your layout or a view -->  
     <script>  
       const publicKey = 'YourPublicKeyHere'; // same as in appsettings.json  
       async function subscribeUser() {  
         const registration = await navigator.serviceWorker.register('/sw.js');  
         const subscription = await registration.pushManager.subscribe({  
           userVisibleOnly: true,  
           applicationServerKey: urlBase64ToUint8Array(publicKey)  
         });  
         await fetch('/api/push/subscribe', {  
           method: 'POST',  
           headers: { 'Content-Type': 'application/json' },  
           body: JSON.stringify(subscription)  
         });  
       }  
       function urlBase64ToUint8Array(base64String) {  
         const padding = '='.repeat((4 - base64String.length % 4) % 4);  
         const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');  
         const rawData = window.atob(base64);  
         return Uint8Array.from([...rawData].map(char => char.charCodeAt(0)));  
       }  
       if ('serviceWorker' in navigator && 'PushManager' in window) {  
         subscribeUser().catch(err => console.error('Push failed:', err));  
       }  
     </script>  
    

Testing
  1. Run your ASP.NET Core app with HTTPS.
  2. Open browser, allow notifications.
  3. Check the browser’s console for any errors.
  4. Trigger a POST to /api/push/send with a message using Postman or JavaScript.

Tips
  1. Always use HTTPS — push will not work without it.
  2. Store subscriptions in a real database for production apps.
  3. Handle pushsubscriptionchange events in the service worker to update expired subscriptions.

Summary

You now have a working Web Push Notifications system in ASP.NET Core. While setting it up involves several steps, it pays off in improved user engagement and real-time communication. I hope this was helpful to you.

Thanks

Kailash Chandra Behera

I am an IT professional with over 13 years of experience in the full software development life cycle for Windows, services, and web-based applications using Microsoft .NET technologies.

1 Comments

Previous Post Next Post

نموذج الاتصال