1

I am trying to setup a single page application with a Web API restful back-end. I used the "OWIN WebAPI SPA Template" to start my project. This template defaults the static file serving to the public/ folder within the solution's root directory. I want to support html5 urls, IE. localhost/madeUpPath which should hit the index.html page. In order to do this, I setup a rewrite rule in the Web.config file:

<system.webServer>
  <rewrite>
      <rules>
          <rule name="Main Rule" stopProcessing="true">
              <match url=".*" />
              <conditions logicalGrouping="MatchAll">
                  <add input="{REQUEST_URI}" pattern="api/" ignoreCase="true" negate="true" />

                  <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                  <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
              </conditions>
              <action type="Rewrite" url="/" />
          </rule>
      </rules>
  </rewrite>
</system.webServer>

The issue I am having is that since the static files live in /public/ the {REQUEST_FILENAME} thinks the file is relative to / and the url localhost/main.css is rewritten to localhost/

I have tried changing the rule to this:

                  <add input="public/{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                  <add input="public/{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />

but that did not work. How can I achieve my desired result? Thank you.

Edit: I found something that seems to work, but isn't exactly what I was looking for.

<rewrite>
    <rules>
        <rule name="Main Rule" stopProcessing="true">
            <match url="([a-zA-Z0-9-_.\/]+\.(css|js|less|json|jpeg|jpg|png|gif|svg|xml|html))$" />
            <action type="Rewrite" url="/public/{R:0}" />
        </rule>
        <rule name="Second Rule" stopProcessing="true">
            <match url=".*" />
            <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            </conditions>
            <action type="Rewrite" url="/" />
        </rule>
    </rules>
</rewrite>

2 Answers 2

1

Firstly, this code doesn't because you're using OWIN server for static files:

           <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>

Could you please to use next code:

<rewrite>
    <rules>
        <rule name="Main Rule" stopProcessing="true">
            <match url="^((?!(api|\.)).)*$" />
            <action type="Rewrite" url="/" />
        </rule>
    </rules>
</rewrite>

Regular expression gives us ability to ignore api and any file paths.

Sign up to request clarification or add additional context in comments.

4 Comments

Can you explain why the rewrite rule for checking for a physical file or directory doesn't work when using owin? I looked through the trace log files and owin strips out the FileSystem path from the request. For example, if I have a main.js file located at c:\TestApp\public\main.js and c:\TestApp is the root of my project and I have the FileSystem property set to new PhysicalFileSystem("./public") and I go to localhost:1337/main.js then IIS thinks that the physical file lives at c:\TestApp\main.js HOW DOES THAT MAKE ANY SENSE?!
As far as your second point, that isn't the goal here. The rewrite rule for ignoring the api path works fine as is. The issue is that when using owin with angular and html5mode enabled I have to use either a rewrite rule or middleware to redirect all non file and non directory requests back to index.html. Everything I have googled tells me to use the rewrite rule I provided, but it simply doesn't work with Owin for the reason in my previous comment.
Regardless of Owin being used, my own observation is that the URL Rewrite Module is still appled. Owin merely inserts itself into the pipeline and I suspect that the URL Rewrite Module happens earlier on in the pipeline before it Owin is reached. Regardless of the exact internals of IIS, Owin and URL Rewrite, we are working perfectly with Owin and with URL Rewrite configuration as per my answer.
This answer needs more upvotes. This is by far the best answer to serve SPA in a Core applications' wwwroot folder. Tried and succeeded other options, but without giving your Angular app a base-href, only this option works by disgarding the API paths and returning every other request to the root. Thank you!
0

We also use Owin to serve content out of a sub folder and the following works perfectly for us:

<rewrite>
  <rules>
    <rule name="Angular Routes" stopProcessing="true">
      <match url=".*" />
      <conditions logicalGrouping="MatchAll">
        <add input="{APPL_PHYSICAL_PATH}public{URL}" matchType="IsFile" ignoreCase="true" negate="true" />
        <add input="{APPL_PHYSICAL_PATH}public{URL}" matchType="IsDirectory" ignoreCase="true" negate="true" />
        <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
      </conditions>
      <action type="Rewrite" url="/" />
    </rule>
  </rules>
</rewrite>

It's very similar to this comment, but I changed their {REQUEST_URI} variables to {URL} so that it will also ignore existing files even if they have query strings, which is necessary for cache busting resources, like site.css?ec99043d9af49f2bd7c2.

Edit: I also just found this Microsoft example which with some tweaking may also work for this scenario, but I haven't tested it myself:

  <rewrite>
    <rules>
      <rule name="Angular Routes" stopProcessing="true">
        <match url=".*" />
      <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
      </conditions>
      <action type="Rewrite" url="/MyApp/" />
      <!--<action type="Rewrite" url="/" />-->
      </rule>
    </rules>
  </rewrite>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.