Leveraging IIS Static File Feature in ASP.NET Core
Introduction:
If you are using IIS as a reverse proxy behind Kestrel web server then you can use the benefits of IIS. IIS has a lot of great built-in modules. StaticFileModule is one of them. Kestrel performance is great but if a request enters managed code, the throughput for that request will be reduced little bit. So, serving static files from IIS native module will be great for performance. Another benefit is that static files will be kernel cached. If you want to know whether using IIS directly for static files will increases your application throughput or not, race (I mean stress test the app). BTW, my main intention in this article is to show you how we can leverage IIS existing feature in ASP.NET Core rather then start another performance debate.
Description:
Note that I am using ASP.NET Core 1.0.0 at the time of writing. It is important that we should restrict IIS native static module to serve only files inside wwwroot folder because there are some sensitive files at root of your IIS application and also restrict it for known files like svg, gif, png, jpeg, etc. that your application is using. Here is updated web.config,
<configuration> <!-- Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380 --> <system.webServer> <staticContent> <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" /> </staticContent> <rewrite> <rules> <rule name="wwwroot"> <match url="([\S]+[.](svg|js|css|png|gif|jpg|jpeg))" /> <action type="Rewrite" url="wwwroot/{R:1}" /> </rule> </rules> </rewrite> <handlers> <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=".\WebApplication2Core.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" /> </system.webServer> </configuration>
In the above web.config, we are caching all static resources for 365 days. Then, we have url rewrite rule which appends wwwroot/ (assuming you are using the same default folder name) in the beginning of every static request path (I am assuming it ends with some known static file extensions). For example, if we have request url like http://site/images/banner1.svg, IIS will rewrite this as http://site/wwwroot/images/banner1.svg before reaching IIS native static file module. Finally, we are mapping handlers for known static file extensions to StaticFileModule module.
You can also comment the static file middleware which may save you a IO request.
Summary:
In this article, I showed you how easily we can leverage some existing IIS modules in ASP.NET Core app. Here we used static file module for potential performance improvement. To check whether this trick will increase your application throughput or not, make sure to race your horses.