Skip to content

Instantly share code, notes, and snippets.

@brandanmajeske
Last active January 5, 2021 08:49
Show Gist options
  • Save brandanmajeske/ec99043d9af49f2bd7c2 to your computer and use it in GitHub Desktop.
Save brandanmajeske/ec99043d9af49f2bd7c2 to your computer and use it in GitHub Desktop.
IIS web.config rewrite rule for MVC/WebAPI with AngularJS in Html5 Mode
<!-- $locationProvider.html5Mode(true) in app.js and <base href="/"> in head tag -->
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
@csfanse
Copy link

csfanse commented Jun 10, 2016

Above code does not work in my case. I have created another web site in IIS(Version 10) other than default web site. The site contains two project. One is portal and other is Web API consumed in that portal. I am using angular components and component routing as well,

@crazyjat
Copy link

crazyjat commented Jan 3, 2018

With Owin 3.1.0 and IIS Express from Visual Studio 2015 this rewrite rule causes all of my static files to be rewritten to the index.html file.

Is there a way to fix that?

Here is my complete web.config file:

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.6" />
    <httpRuntime targetFramework="4.6" />
  </system.web>
  
  <!-- Configure a transparent IIS: No static files, no handlers. -->
  <system.webServer>
    <!-- runAllManagedModulesForAllRequests: Make sure that we have OWIN handle static files, too. -->
    <modules runAllManagedModulesForAllRequests="true" />
    
    <rewrite>
      <rules>
        <rule name="html5mode" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
    
    <!-- Disable all static content handling in the IIS -->
    <staticContent>
      <clear />
    </staticContent>
    
    <!-- Remove all handlers -->
    <handlers>
      <clear />
    </handlers>
  </system.webServer>
  
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

@crazyjat
Copy link

crazyjat commented Jan 4, 2018

I found that the following rewrite rule works for a Owin 3.1.0 WebApi SPA Template project hosted with IIS Express from Visual Studio 2015. Since this project template uses a public folder to store all of the html the above rewrite rule will not work since the {REQUEST_FILENAME} variable does not include the public folder in the path. For example, if my project is located at c:\testapp and my project folder contains a public folder (so c:\testapp\public) that contains my html, css and javascript and the browser requests index.js the {REQUEST_FILENAME} variable will be c:\testapp\index.js. Why this happens makes no sense, but I have verified that it does with trace logging. To fix my issue I had to use this rewrite rule.


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

@digrizzz
Copy link

digrizzz commented Sep 28, 2018

thanks @craztjat ! That was helpfull. Alswo i want to add for those from google like me: you may also should include rule for negating xhr (if you're adding scripts dynamically for example): <add input="{HTTP_X_Requested_With}" pattern="^XMLHttpRequest$" negate="true" />

@sascalas
Copy link

sascalas commented Jan 5, 2021

thanks @craztjat ! That was helpfull. Alswo i want to add for those from google like me: you may also should include rule for negating xhr (if you're adding scripts dynamically for example): <add input="{HTTP_X_Requested_With}" pattern="^XMLHttpRequest$" negate="true" />

Gracias compañero. Era lo que necesitaba para que terminara de funcionar mi aplicación con MVC + Angular. Copio finalmente como queda mi ReWrite:

   <rewrite>
   <rules>
     <!--Regla para que no filtre las llamadas a Swagger-->
     <rule name="OpenLIS.API.Swagger" stopProcessing="true" enabled="true">
       <match url="^(swagger)" ignoreCase="true" />
       <action type="None" />
     </rule>
     <!--Regla para que no filtre las llamadas a la API-->
     <rule name="OpenLIS.API.Rule" stopProcessing="true" enabled="true">
       <match url="^(api)"  ignoreCase="true"/>
       <action type="None" />
     </rule>
     <!--Regla para que si lo que se llama no existe (Ni es un archivo, ni es un directorio, ni es una llamada AJAX) entonces
     se redirija al root de angular, para que pueda rutear la applicación.
     Se añade regla XHR para que no filtre las llamadas desde AJAX que utilizan .js que no controlamos como jQuery. 
     Usa el objeto XMLHttpRequest(XHR) para hacer llamadas API del lado del servidor 
     desde el navegador.-->
     <rule name="OpenLIS.Angular.Rule" stopProcessing="true" enabled="true">
       <match url="(.*)" />
       <conditions logicalGrouping="MatchAll">
         <add input="{HTTP_X_Requested_With}" pattern="^XMLHttpRequest$" negate="true" />
         <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
         <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
       </conditions>
       <!--<action type="Redirect" url="." /> -->
       <action type="Rewrite" url="." />
     </rule>
   </rules>
</rewrite>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment