title: Blazor WASM - PWA - Offline behaviour with server-side requests
body: <p>I've created a new project using the default project template for a Blazor Webassembly app, with identity, asp.net core hosted, and PWA options checked.  This gives us a WASM blazor SPA app with some basic offline PWA ability, and a server-side asp.net core app.</p>
  
  <p>When authenticating with identity, the pages are served by the Server app.  As such, they can't be reached when the app is running offline.  This is to be expected, but the user experience (out of the box) in this scenario is poor with default 404, or "you have no internet" pages rendered by the browser.</p>
  
  <p>I'd like to clean this up so the user is safely/gracefully warned about the failure to GET the remote pages.  I started to look at the service-worker.js provided by the template and it already contains code to deal with "connect" and "identity" urls and ensure they are fetched from the server-side.  I've attempted to add to this by using the approach shown here - <a href="https://googlechrome.github.io/samples/service-worker/custom-offline-page/" rel="nofollow noreferrer">https://googlechrome.github.io/samples/service-worker/custom-offline-page/</a></p>
  
  <pre><code>async function onFetch(event) {
      let cachedResponse = null;
  
      var shouldServeIndexHtml = true;
  
      console.info('Service worker: onFetch');
  
      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
          shouldServeIndexHtml = event.request.mode === 'navigate'
              &amp;&amp; !event.request.url.includes('/connect/')
              &amp;&amp; !event.request.url.includes('/Identity/');
  
          const request = shouldServeIndexHtml ? 'index.html' : event.request;
          const cache = await caches.open(cacheName);
          cachedResponse = await cache.match(request);
      }
  
      console.info('Service worker event.request.url: ' + event.request.url);
  
      if (cachedResponse != null) {
          console.info('Service worker we have cachedResponse: ' + cachedResponse.url);
          return cachedResponse
  
      } else {
          console.info('Service worker cachedResponse is null, starting fetch ');
  
          try {
              const networkResponse = await fetch(event.request);
              return networkResponse;
          } catch (error) {
              // catch is only triggered if an exception is thrown, which is likely
              // due to a network error.
              // If fetch() returns a valid HTTP response with a response code in
              // the 4xx or 5xx range, the catch() will NOT be called.
              console.log('Fetch failed; returning offline page instead.', error);
  
              console.log('Fetch failed shouldServeIndexHtml ',shouldServeIndexHtml);
  
              if (shouldServeIndexHtml == false) {
  
                  console.log('Fetch failed, attempting fallback');
  
                  const request = 'index.html';
                  const cache = await caches.open(cacheName);
                  cachedResponse = await cache.match(request);
  
                  if (cachedResponse != null) {
                      console.info('Service worker we have fallback cachedResponse: ' + cachedResponse.url);
                      return cachedResponse
  
                  } else {
                      console.info('Service worker fallback cachedResponse is null');
                  }
              }
          }
  
  
      }
  
  }
  </code></pre>
  
  <p>Code is rough at the moment, apologies!</p>
  
  <p>This <strong><em>almost</em></strong> works.  If a GET is attempted to a server page (identified with shouldServeIndexHtml = false), it now attempts the fetch in a try/catch.  The catch then does fire, and I try to route to "index.html", but here is where it all falls down.  This ends with the Blazor client-side Router going to the NotFound layout.</p>
  
  <p>This makes me think that this isn't the best approach to this, but has anyone else attempted to sort this out using the service worker, or via another method?</p>