I am trying to configure a directory structure in an IIS website to host multiple versions of a Blazor WebAssembly standalone app, with each version residing separately in its own directory. I want to use rewrite rules in the web.config
at the root level to determine which version of the app is served, based on a cookie (as shown in this answer). However, Blazor needs to have its own web.config
in its directory, with rewrite rules to serve its wwwroot
subdirectory and provide SPA fallback routing. I can't get the two sets of rewrite rules to work together for the same request.
Take the following simplified structure. I have added a hello.txt
file to the wwwroot
directory of the Blazor app for testing.
Default Web Site
├─ web.config
└─ v1
├─ web.config
└─ wwwroot
├─ index.html
└─ hello.txt
I want to be able to access hello.txt
through http://localhost/hello.txt. I have configured the web.config
at the website root level like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Rewrite to v1" stopProcessing="false">
<match url="^(?!v1).*" />
<action type="Rewrite" url="v1\{R:0}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
And I have copied the web.config
generated by Blazor into the v1
directory (relevant excerpt below):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Serve subdir">
<match url=".*" />
<action type="Rewrite" url="wwwroot\{R:0}" />
</rule>
<rule name="SPA fallback routing" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="wwwroot\index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
The one-level rewrite works when I access http://localhost/v1/hello.txt, but the two-level rewrite doesn't work for http://localhost/hello.txt; see image below. Note that changing the rewrites to redirects allows the file to be served successfully (but causes the URL in the address bar to change, which I don't want).
Is there a way of getting this to work, or it is some limitation of the URL Rewrite Module? Microsoft seems to claim that multiple configuration levels are supported in the URL Rewrite Module Configuration Reference:
Rules Inheritance
If rules are defined on multiple configuration levels, the URL Rewrite Module evaluates the rules in the following order:
- Evaluate all the global rules.
- Evaluate a rule set that includes distributed rules from parent configuration levels as well as rules from the current configuration level. The evaluation is performed in a parent-to-child order, which means that parent rules are evaluated first and the rules defined on a last child level are evaluated last.
I'm aware that I can make the web.config
at the website root level reference Blazor's wwwroot
subdirectory directly (through url="v1\wwwroot\{R:0}"
). However, I don't want to do this. I will eventually be extending the outer web.config
to support other versions of my app (v2
, v3
, …), which may or may not also have a wwwroot
subdirectory, depending on future versions of Blazor and whether we keep using Blazor. Hence, it would be much cleaner to maintain any version-specific rewrites to inner subdirectories in the Blazor version-specific web.config
.
I've tried using Failed Request Tracing. The outer rule, Rewrite to v1
, is logged to run successfully. There is no mention of the inner rule, Rewrite to wwwroot
.