title: How do ASP.NET Core's "asp-fallback-*" CDN tag helpers work?
body: <p>I understand what the <code>asp-fallback-*</code> tag helpers do. What I don't understand is how.</p>
  <p>For example:</p>
  <pre class="lang-html prettyprint-override"><code>&lt;link rel=&quot;stylesheet&quot;
        href=&quot;//ajax.aspnetcdn.com/ajax/bootstrap/3.3.5/css/bootstrap.min.css&quot;
        asp-fallback-href=&quot;~/lib/bootstrap/dist/css/bootstrap.min.css&quot;
        asp-fallback-test-class=&quot;sr-only&quot;
        asp-fallback-test-property=&quot;position&quot;
        asp-fallback-test-value=&quot;absolute&quot; /&gt;
  </code></pre>
  <p>This loads bootstrap from the CDN, and loads the local copy if the CDN is down.</p>
  <p>But how does it decide to do that? I assume it checks <code>asp-fallback-test-class</code>, <code>asp-fallback-test-property</code>, and <code>asp-fallback-test-value</code>. But what do those attributes mean?</p>
  <p>If I want to hook up some other library off a CDN, I'll need to supply something for those, but I'm not sure what to put there.</p>
  <p>There are lots of examples of this in action, but I can't find explanations about how this works.</p>
  <p><em>UPDATE</em><br />
  I'm not really trying to understand how the tag helpers work - how they render, and so on. I'm trying to understand how to choose values for those attributes. For example, the jQuery fallback script usually has <code>asp-fallback-test=&quot;window.jQuery&quot;</code> which makes sense - it's a test to see if jQuery has loaded. But the ones I've shown above are quite different. How does one choose them? If I want to use some other CDN delivered library, I'll need to specify values for those attributes... what would I use? Why were those ones chosen for bootstrap?</p>
  <p><em>UPDATE 2</em><br />
  To understand how the fallback process itself works, and how those tags are written, see @KirkLarkin's answer. To understand why those test values were used, see my answer.</p>
  <p><em>UPDATE 3</em><br />
  In <a href="https://getbootstrap.com/docs/5.1/migration/#helpers" rel="nofollow noreferrer">bootstrap 5</a> the <code>sr-only</code> class was renamed to <code>visually-hidden</code>.</p>