4

I have a WebApp with an AspNetCore WebAPI + AngularApp on Azure with IIS rewrite rules in my Web.Config based on this article: https://weblog.west-wind.com/posts/2017/Apr/27/IIS-and-ASPNET-Core-Rewrite-Rules-for-AspNetCoreModule

I would like to avoid rewriting on Swagger, so I added this rule as the first rule:

<rule name="swagger" enabled="true" stopProcessing="true">
  <match url="swagger/.*" />
  <action type="None" />
</rule>

Based on this website: https://www.regextester.com/ enter image description here

The rules is supposed to exclude swagger/ and all the subfolders and files too. But It s not the case. image

This is what I can see when I open http://[MYWEBSITE]/swagger/ image

The Angular app works correctly.

I already made some search about that:

Thanks for your help.


EDIT 1:

Just to let you know, with the default web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>

    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="dotnet" arguments=".\[MYWEBAPP].Api.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" />
  </system.webServer>
</configuration>

I can correctly see Swagger working: enter image description here


EDIT 2:

During my tests, I removed the rewrite rules to focus only on the Handlers and I noticed that theses rules make problem:

It s normal, Swagger is build in the .NetCore WebApi. I m looking for a way to exclude a specific folder from a handlers.

Based on this response: IIS Handlers exclude a Directory when processing htm requests

I created a web.config in 'D:\home\site\wwwroot\wwwroot\swagger' on Azure with the following configuration:

<system.webServer>
     <handlers>
       <remove name="StaticFileModuleHtml" />
       <remove name="StaticFileModuleJs" />
       <remove name="StaticFileModuleCss" />
       <remove name="StaticFileModulePng" />
     </handlers>
</system.webServer>

EDIT 3:

Clearly the problem comes from the Static handlers. If I want to use Swagger, I need to disable them. If I want to access to my angular App, I need to add them.

I saw here: https://github.com/domaindrivendev/Swashbuckle.AspNetCore#swashbuckleaspnetcorecli

That it seems possible to extract the content from the SwaggerUi directly in a folder on built, but currently, the Nugget Package is not available: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/601

I will keep you update. If someone has an idea, it will be helpful. I m probalbly not the only to try to do that :).

But the problem is still there.

Cedric Arnould
  • 1,991
  • 4
  • 29
  • 49

2 Answers2

4

I finally found a solution!

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="wwwroot-static" stopProcessing="true">
          <match url="([\S]+[.](html|htm|svg|js|css|png|gif|jpg|jpeg))" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_URI}" pattern="swagger/" negate="true" />
          </conditions>
          <action type="Rewrite" url="wwwroot/{R:1}" />
        </rule>
        <rule name="empty-root-index" stopProcessing="true">
          <match url="^$" />
          <action type="Rewrite" url="wwwroot/index.html" />
        </rule>
        <rule name="AngularJS-Html5-Routes" 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" />
            <add input="{REQUEST_URI}" pattern="swagger/" negate="true" />
          </conditions>
          <action type="Rewrite" url="wwwroot/index.html" />
        </rule>
      </rules>
    </rewrite>
    <handlers>
      <add name="StaticFileModuleHtml" path="*.htm*" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="StaticFileModuleSvg" path="*.svg" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="StaticFileModuleJs" path="*.js" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="StaticFileModuleCss" path="*.css" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="StaticFileModuleJpeg" path="*.jpeg" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="StaticFileModuleJpg" path="*.jpg" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="StaticFileModulePng" path="*.png" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="StaticFileModuleGif" path="*.gif" verb="*" modules="StaticFileModule" resourceType="File" requireAccess="Read" />
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="dotnet" arguments=".\[MYWEBAPP].dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" />
  </system.webServer>
</configuration>

My mistake during the Edit 2 was to create a Swagger folder in wwwroot/wwwroot instead of wwwroot/ directly.

Here is the web.config to add in wwwroot/swagger:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <!--We need to add this web.config to avoid conflict on Azure between Angular App and Swagger -->
      <remove name="StaticFileModuleHtml" />
      <remove name="StaticFileModuleSvg" />
      <remove name="StaticFileModuleJs" />
      <remove name="StaticFileModuleCss" />
      <remove name="StaticFileModuleJpeg" />
      <remove name="StaticFileModuleJpg" />
      <remove name="StaticFileModulePng" />
      <remove name="StaticFileModuleGif" />
    </handlers>
  </system.webServer>
</configuration>

You can now access to:

  • http(s)://[MYWEBAPP]
  • http(s)://[MYWEBAPP]/[ANGULAR ROUTE]
  • http(s)://[MYWEBAPP]/Swagger

I hope it will help someone :). If you have any questions, please ask.

Cedric Arnould
  • 1,991
  • 4
  • 29
  • 49
  • This seems to work indeed, thanks! Except for the web.config file, which needs to be put in the web app's root. So instead of - /wwwwroot/swagger/web.config I've moved it to: - /swagger/web.config – geerth Mar 14 '18 at 13:24
  • Hi, happy that my solution worked for you :) Maybe my answer is not enought clear, I wanted to say that if you put the web.config for swagger in 'D:\home\site\wwwroot\swagger', it works. My mistake at the begining was to put it in 'D:\home\site\wwwroot\wwwroot\swagger' which doesnt work. Did I understand well your answer? – Cedric Arnould Mar 14 '18 at 15:22
  • You shouldn't put server configuration files into the wwwroot folder as it will be served as static content. Hence I've put the config file into the swagger folder outside wwwroot and then it worked! :) – geerth Mar 20 '18 at 08:38
  • It s hard for me to know which wwwroot you are talking, because there is 2 wwwroot, 'wwwroot' and 'wwwroot/wwwroot'. On my side, if I put the web.config for swagger in 'D:\home\site\wwwroot\swagger', it works. My solution is for Azure, you can probably adapt for other platforms. Maybe you are not using Azure and your configuration is different than mine. The most important is that it works for you :). – Cedric Arnould Mar 20 '18 at 19:34
  • You better use a `...` within the root web.config. And do all the removals there. This is much clearer and that location does not have to ever physically exist. – Vertigo Aug 26 '19 at 13:10
  • Thanks for your comment, I worked on it a long time ago and no time to work on it again to test your suggestion sorry :(. But it could be interesting for someone else :) – Cedric Arnould Aug 26 '19 at 20:56
2

First of all, because Swagger does not make a real folder, so it is not a perfect idea to make a folder in wwwroot named swagger and make that web.config inside of it. I consider that the default address for your swagger UI is: localhost:[random-port-number]/swagger/index.html. It can be different based on your swagger version and you can also change it to something else like below:

app.UseSwagger(c =>
{
    c.RouteTemplate = "SampleApi/swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/SampleApi/swagger/v1/swagger.json", "Sample API");
    c.RoutePrefix = "SampleApi/swagger";
});

For more information see this article. The version of my Swashbuckle.AspNetCore is 4.0.1 I also added API to the routes in order to be able to use your Microsoft web APIs in your project from font-end by React or Angular or anything else, you just need to add this to your main web.config in the project:

<rules>
    <rule name="wwwroot-static" stopProcessing="true">
      <match url="([\S]+[.](html|htm|svg|js|css|png|gif|jpg|jpeg|ico|axd))" />
       <!--Handle static file requests and server them from the wwwroot--> 
      <conditions logicalGrouping="MatchAll">
        <add input="{HTTP_METHOD}" pattern="GET|HEAD" />
        <add input="{REQUEST_URI}" pattern="/swagger/.*" negate="true" />
      </conditions>
      <action type="Rewrite" url="wwwroot/{R:1}" />
    </rule>

    <rule name="html5-routes" stopProcessing="true">
      <match url=".*" />
      <!-- Handle all paths except /api/ and pass the route onto the wwwroot/index.html -->
      <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <!-- Add rule to negate file requests e.g. css/html/images-->
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        <!-- Add rule to negate directories-->
        <add input="{REQUEST_URI}" pattern="^/api/" negate="true" />
        <add input="{REQUEST_URI}" pattern="/swagger/.*" negate="true" />
        <!-- Add rule to negate paths and let them through the MVC-->
        <add input="{HTTP_METHOD}" pattern="GET|HEAD" />
      </conditions>
      <action type="Rewrite" url="wwwroot/index.html" />
    </rule>
</rules>
Arash MAS
  • 128
  • 1
  • 7