How to define custom web.config in .Net Core 2 for IIS publish? - iis

VS will generate (and override) a web.config file as part of publishing to IIS. I have various items I need to include in the file (like extending the file upload max size limit, redirecting to HTTPS, etc.). I am currently having to copy and paste the contents into the file after every publish.
Is there a way to define the contents of the web.config file that Visual Studio generates when publishing a .NET Core 2 web app for IIS?

not sure if you solved this, but if anyone else runs across this problem, I had this issue and finally went looking for the source code for the transform task. it contains some logging, so I ran the dotnet publish with a /v:n parameter, which sets the logging verbosity to "normal":
dotnet publish src\MyProject -o ..\..\publish /v:n
when I ran this, I saw this in the output:
_TransformWebConfig:
No web.config found. Creating 'C:\Development\MyProject\publish\web.config'
even though there is a web.config in the project. I changed the properties of the web.config "Copy to Output Directory" to "Always", and now the web.config in my project gets merged with the auto-generated contents.
my csproj now has this in it:
<None Include="web.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
and the publish output has:
_TransformWebConfig:
Updating web.config at 'C:\Development\MyProject\publish\web.config'
NOTE: if you are publishing to an existing directory that already has web.config in it, it will update that file. (i.e., an old publish). if you don't specify an output directory, it will publish to something like /bin/Debug/net471/publish/, which may have old files in it.
NOTE2: you still need the Sdk="Microsoft.NET.Sdk.Web" attribute on the Project node in your csproj file, or it won't even bother looking for Web.configs.
for reference, here is the task source code:
https://github.com/aspnet/websdk/blob/master/src/Publish/Microsoft.NET.Sdk.Publish.Tasks/Tasks/TransformWebConfig.cs

I finally got back to this and wound up using a transform:
Create a web.release.config file in the root of the project
Set that file's properties to Build Action = None so it doesn't get copied directly to the destination folder
Use the transformation syntax to define the sections that need to be inserted:
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<location>
<system.webServer>
<security xdt:Transform="Insert">
<requestFiltering>
<requestLimits maxAllowedContentLength="209715200" />
</requestFiltering>
</security>
<rewrite xdt:Transform="Insert">
<rules>
<rule name="HTTP/S to HTTPS Redirect" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{SERVER_PORT_SECURE}" pattern="^0$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
<modules xdt:Transform="Insert" runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule" />
</modules>
</system.webServer>
</location>
</configuration>

Related

IIS 8.5 cache issue on rewrite if file not exists

I need to achieve in IIS the following:
check for changed .txt files in dir with url http://server/dir/test.txt without cache
rewrite url to empty.txt if file does not exist
My configuration:
<rewrite>
<rules>
<rule name="test-txt" patternSyntax="Wildcard" stopProcessing="true">
<match url="*.txt" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="empty.txt" />
</rule>
</rules>
</rewrite>
<caching>
<profiles>
<add extension=".txt" policy="DisableCache" kernelCachePolicy="DisableCache" />
</profiles>
</caching>
If file is changed, I get code 200 and actual content. Works as expected.
If file not changed - 304. Works as expected.
If file is deleted, after first check I get error 404.0. Why?
After second request I get code 200 and content of empty.txt. Works as expected.
If I create file at that moment, it works as expected. But if make requests in short time intervals (every 3-4 seconds), it doesn't matter any more if file test.txt exists or not, I get code 304 or content of empty.txt if I change it. But if I stop requesting file for some minutes, it works again as expected.
It looks like IIS has some sort of cache for static file checking. How to make it work as expected with static files only? (and without getting error 404 if possible)
It is not output caching, its just about browser cache.
So if you want to prevent cache for specific folder, please place this in the root web.config of your website/application. In this case, you have to disable location path for both example.txt and dir directory
<location path="dir">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
</system.webServer>
</location>
<location path="empty.txt">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
</system.webServer>
</location>
If you want to disable browser cache for all site, please just set
<clientCache cacheControlMode="DisableCache" />
without location attribute.
Your rule works fine on my side, so you just have to disable client side cache for the required folder/file.

I am unable to deploy my nextjs application on azure

I have been trying to deploy my next.js application on azure devops project service.
I have set up CI and CD of my project which is linked with the azure repos.
Even if my pipeline succeeds I get "INTERNAL SERVER ERROR" or " Application error",even though the application runs fine on my local.
I have tried a node applicaton , which runs with the same pipleline tasks.
I have tried adding a web.config file and still no luck with it.
Can anyone suggest me what I could me missing?
Adding a web.config file
Disabling a web.config option in release pipeline
Adding new tasks in the pipelines such as npm run build
My web.config file is as follows:
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<!-- All other URLs are mapped to the node.js site entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="server.js"/>
</rule>
</rules>
</rewrite>
<!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<!-- Make sure error responses are left untouched -->
<httpErrors existingResponse="PassThrough" />
<!--
You can control how Node is hosted within IIS using the following options:
* watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
* node_env: will be propagated to node as NODE_ENV environment variable
* debuggingEnabled - controls whether the built-in debugger is enabled
See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
-->
<!--<iisnode watchedFiles="web.config;*.js"/>-->
My application end point gives application error result, even though I think I have completed almost whole procedure.

How to configure web.config for multiple virtual applications in Azure App Service?

I am trying to have multiple Node.js applications working in parallel in the same Azure App Service instance. I tried making a virtual application per Node.js app but I constantly get a server error (code 500). I use ZipDeploy or Azure DevOps to deploy my applications.
I suspect the problem might be that the web.config files associated with my applications is incorrect.
Here are some details on my setup:
In the Application settings menu of my App Service instance, I went to the Virtual applications and directories settings and put the following:
/ site\wwwroot Application x
/mysite1 site\wwwroot\mysite1 Application x
/mysite2 site\wwwroot\mysite2 Application x
My wwwroot directory looks as follows. To make sure the problem doesn't come from the code itself, I used the same Node.js application for all three:
index.html
server.js
scripts
web.config (*)
----- mysite1
|----- index.html
|----- server.js
|----- scripts
|----- web.config (**)
----- mysite2
|----- index.html
|----- server.js
|----- scripts
|----- web.config (***)
I use the default web.config file (provided by Kudu) for the three of them:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<webSocket enabled="false" />
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^server.js\/debug[\/]?" />
</rule>
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="server.js"/>
</rule>
</rules>
</rewrite>
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin"/>
</hiddenSegments>
</requestFiltering>
</security>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
Using this configuration, I can reach https://myappservice.azurewebsites.net/ without issue but https://myappservice.azurewebsites.net/mysite1 only returns a server error.
I tried taking off the handlers from the web.config files in subdirectories (** and ***) as instructed in similar questions but to no avail.
What is the correct configuration for these three files? I suppose the rewrite rules need to be adjusted but I am unsure what is the exact expected value for each.
I finally managed to pinpoint the exact problem through the IIS logs (/LogFiles/W3SVC.../ on Kudu) :
ModuleName="RewriteModule", Notification="SEND_RESPONSE", HttpStatus="500", HttpReason="URL Rewrite Module Error.", HttpSubStatus="52", ErrorCode="Cannot create a file when that file already exists.
(0x800700b7)", ConfigExceptionInfo="\\?\D:\home\site\wwwroot\mysite1\web.config ( 16) :Cannot add duplicate collection entry of type 'rule' with unique key attribute 'name' set to 'NodeInspector'
"
What needed to be changed were the handler and rule names in the child web.config file, so that they wouldn't clash with the names in the parent web.config file. Everything works correctly now.
You could change Virtual applications and directories settings as below:
/ site\wwwroot Application x
/mysite1 site\mysite1 Application x
/mysite2 site\mysite2 Application x
When you deploy with zipdeploy or DevOps, the site name and Destination URL is like below:
For more details you could refer to Deploying multiple virtual directories to a single Azure Website.

How can I apply <clientCache /> settings to a specific extension in IIS?

I am hosting a web app on Azure with the following Web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".text" mimeType="text/plain" />
<clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
</staticContent>
</system.webServer>
</configuration>
This works but I would like to vary the cache age by extension. I would like to set the max age of .html files to 1 day and the max age of everything else to 365 days. The reason being that all of the assets in the html have their filenames revved on change and are served from a CDN, so they never need to expire, but the html pages themselves need to always be fresh so the user can see new content.
I see that the <location> element allows filtering the Web.config to specific locations, but I don't see a way to limit it to certain extensions.
Please note that I don't require being able to do this in the Web.config: any means possible with an Azure Web App is fine.
As others have mentioned it is not possible so I would like to suggest a workaround to do the job.
You can take advantage of the capabilities of the URL Rewrite Module by creating an outbound rule to replace Cache-Control header of the html files.
Here's the config.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".text" mimeType="text/plain" />
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" />
</staticContent>
<rewrite>
<outboundRules>
<rule name="RewriteCacheControlForHTMLFiles" preCondition="FileEndsWithHtml">
<match serverVariable="RESPONSE_Cache_Control" pattern=".*" />
<action type="Rewrite" value="max-age=86400" />
</rule>
<preConditions>
<preCondition name="FileEndsWithHtml">
<add input="{REQUEST_FILENAME}" pattern="\.html$" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
A screenshot of my test:
Are these files (html vs content) in separate folders?
If so, you can setup a folder specific caching age
<configuration>
<location path="[html files path]">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="[your requirement]" ></clientCache>
</staticContent>
</system.webServer>
</location>
</configuration>
Unfortunately the <location> element doesn't support regex or wildcards so you won't be able to do exactly what you are asking.
I can think of a couple of ways to achieve your goal though. The first is to write an http module that intercepts requests to images and changes the caching headers.
The other option is to leave your html unchanged but to move all your images to an images folder. You could then set a caching rule on that folder. You could use a redirect rule to redirect requests for images to that images folder. If you choose this path I can give you more information about how you might set it up.

Deploying Express 4.x app to Windows Azure

The new version of Express separates the modules from the "server" file. It now lives in /bin/www and I'd prefer to keep this convention if possible.
In the package.json file, the "start" script clearly points to the right place, but this is seemingly ignored by Azure.
How do I deploy an Express 4.x app without having a server.js file in the root directory? All I need to do is make it automatically call node ./bin/www instead of node server.js. Is there another root configuration file I can add specific to the cloud host (Azure?) This is how I got this working in Heroku, etc.
updated answer
The Azure team has since fixed this internally. A newly deployed express 4 app should work just fine on Azure Websites without any additional changes.
original answer
I'll start with the tl;dr. Create a web.config file in the root of your application and use this xml.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<!--
By default IIS will block requests going to the bin directory for security reasons.
We need to disable this since that's where Express has put the application entry point.
-->
<security>
<requestFiltering>
<hiddenSegments>
<remove segment="bin" />
</hiddenSegments>
</requestFiltering>
</security>
<handlers>
<!-- Indicates that the www file is a node.js entry point -->
<add name="iisnode" path="/bin/www" verb="*" modules="iisnode"/>
</handlers>
<rewrite>
<rules>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^bin\/www\/debug[\/]?" />
</rule>
<!--
First we consider whether the incoming URL matches a physical file in the /public folder.
This means IIS will handle your static resources, and you don't have to use express.static
-->
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}"/>
</rule>
<!-- All other URLs are mapped to the node.js entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="/bin/www"/>
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
This is a bit of a mess and took a while to track down. I really wish it was smart enough to look at package.json, but this is what we have to deal with for now. Normally Azure determine if it is a Node application by checking for an app.js or server.js file. If it finds that file, it will automatically create a web.config file very similar to what is above. In this case, it will detect app.js, but unlike 99% of other node applications, that's not actually the entry point. What we have to do is change the entry point to /bin/www like shown above.
The other issue we run into is that by default IIS blocks requests to the bin folder for security reasons. We can either rename the express bin folder, or tell IIS to get over it. That's what the hiddenSegments part of the xml file is for.

Resources