Popular blog tags

How to Create Progressive Web Applications with ASP.NET Core Blazor WebAssembly step by step?


.Net 8.x



.Net 5.x

Step 1:Create  a Web Applications with ASP.NET Core Blazor WebAssembly( Progressive Web Applications is  not checked)

git github.com


Step 2:Create a Progressive Web Applications with ASP.NET Core Blazor WebAssembly(Progressive Web Applications checked),then overwrite old project.

git to github.com


Step 3:Some of codes have changed



<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

   + <ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>

    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.5" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.5" PrivateAssets="all" />
    <PackageReference Include="System.Net.Http.Json" Version="5.0.0" />

 + <ItemGroup>
 +   <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
 + </ItemGroup>


files changed


wwwroot/index.html changed

<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="Nop.BlazorWebassembly.PWA.styles.css" rel="stylesheet" />
  +  <link href="manifest.json" rel="manifest" />
  +  <link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />

    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    <script src="_framework/blazor.webassembly.js"></script>
   + <script>navigator.serviceWorker.register('service-worker.js');</script>




This JSON file is the root heart of the PWA. This is an industrial standard life. In this file we will declare and setup the PWA.


  "name": "Nop.BlazorWebassembly.PWA",
  "short_name": "Nop.BlazorWebassembly.PWA",
  "start_url": "./",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#03173d",
  "icons": [
      "src": "icon-512.png",
      "type": "image/png",
      "sizes": "512x512"

 the JSON nodes in the manifest.json

name – Display name of the Application
short_name – The short name of our application
start_url – Denotes the Root Directory
background_color – We can set the background color of the application
theme_color – Sets theme color of the application
icons – The desktop icon of our application


Step 1:Creating PWA with Blazor WebAssembly and Enable the Progressive Web Application Option

Choose Blazor WebAssembly and Enable the Progressive Web Application Option。

In order to create PWA, we need to choose Blazor WebAssembly App, since PWA always does not have a server. We also need to enable the Progressive Web Application as shown below. By enabling, it will turn our Blazor WebAssembly Application into a Progressive Web Application.

Step 2:

We can see four new files as icon-512.png, manifest.json, service-worker.js, and service-worker.published.js
The Desktop Icon for our application, which is the default blazor icon


service-worker.js file contains below details.  

Service Worker 一个用于在 web 浏览器后台运行并拦截 HTTP 请求的脚本的 W3C 标准 API.


// Caution! Be sure you understand the caveats before publishing an application with
// offline support. See https://aka.ms/blazor-offline-considerations

self.addEventListener('install', event => event.waitUntil(onInstall(event)));
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));

const cacheNamePrefix = 'offline-cache-';
const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/ ];
const offlineAssetsExclude = [ /^service-worker\.js$/ ];

async function onInstall(event) {
    console.info('Service worker: Install');

    // Fetch and cache all matching items from the assets manifest
    const assetsRequests = self.assetsManifest.assets
        .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
        .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
        .map(asset => new Request(asset.url, { integrity: asset.hash }));
    await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));

async function onActivate(event) {
    console.info('Service worker: Activate');

    // Delete unused caches
    const cacheKeys = await caches.keys();
    await Promise.all(cacheKeys
        .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
        .map(key => caches.delete(key)));

async function onFetch(event) {
    let cachedResponse = null;
    if (event.request.method === 'GET') {
        // For all navigation requests, try to serve index.html from cache
        // If you need some URLs to be server-rendered, edit the following check to exclude those URLs
        const shouldServeIndexHtml = event.request.mode === 'navigate';

        const request = shouldServeIndexHtml ? 'index.html' : event.request;
        const cache = await caches.open(cacheName);
        cachedResponse = await cache.match(request);

    return cachedResponse || fetch(event.request);

service-worker.js file contains below details.


// In development, always fetch from the network and do not enable offline support.
// This is because caching would make development more difficult (changes would not
// be reflected on the first load after each change).

self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
self.addEventListener('install', event => event.waitUntil(onInstall(event)));

async function onInstall(event) {
    console.info('Service worker: Install');

async function onFetch(event) {
    let cachedResponse = null;
    const cache = await caches.open('blazor_pwa');
    if (event.request.method === 'GET') {
        const request = event.request;
        cachedResponse = await caches.match(request);
        if (cachedResponse) {
            return cachedResponse;
        var resp = await fetch(event.request)
        cache.put(event.request, resp.clone());
        return resp;

    return fetch(event.request);


Sending push notifications

Like any other PWA, a Blazor WebAssembly PWA can receive push notifications from a backend server. The server can send push notifications at any time, even when the user isn't actively using the app.




Useful links

Build Progressive Web Applications With Blazor WebAssembly


2.使用Blazor WebAssembly创建PWA应用图解