Replacing IIS rewrite rules in web.config transform - asp.net

I have some IIS rewrite rules that I want to vary by environment. The development rewrite rules are in the web.config file, then at the end of the web.test.config file I have:
<appSettings>
...Some app settings tranforms here
</appSettings>
<system.webserver>
<rewrite xdt:Transform="Replace">
<rules>
... rules here
</rules>
</rewrite>
</system.webserver>
</configuration>
My app settings are getting transformed when I deploy to test, but by IIS rewrite rules are not. I was hoping the entire <rewrite> section would simply be replaced with the one in the transform file (as per http://msdn.microsoft.com/en-us/library/dd465326.aspx), but nothing is changing.
I have tried putting xdt:Transform="Replace" xdt:Locator="Match(name)"> on the individual rules too:
<rule name="Test rule" stopProcessing="true" xdt:Transform="Replace" xdt:Locator="Match(name)">
But again this makes no difference.
Is it even possible to replace rewrite rules in the web.config and if so, what am I missing?

As I didn't have any rewrite rules in my main web.config, the Replace transform didn't work. I successfully used the Insert transform, as below:
<system.webServer>
<rewrite xdt:Transform="Insert">
<rules>
<rule name="CanonicalHostNameRule1">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www\.mysite\.com$" negate="true" />
</conditions>
<action type="Redirect" url="http://www.mysite.com/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>

There is a lot of answers here with examples which is a good thing, but I think few details are missing. I have wrote about this in my website, the key point here is to add xdt:Transform="Insert" in the root tag hierarchy you want to be added for the respective environment.
By default you have your Web.config file, but you have also Web.Debug.config and Web.Release.config as seen in the image below:
Lets say you want to added a redirection from http to https in your release of the application. Then edit Web.Release.config and add following lines:
<?xml version="1.0"?>
.....
<system.webServer>
<rewrite xdt:Transform="Insert">
<rules>
......
</rules>
</rewrite>
</system.webServer>
</configuration>
So next time you publish your project the tag with rewrite and its sub-content will be added to web.config file.
To see that before you publish, right click on Web.Release.config and click Preview Transform.
You will see the difference between initial version and release version.
Reference:
HTTP to HTTPS Redirect - IIS 8.5 not working properly
Microsoft Web.Config file transformations
Disclaimer: the link of this guideline refer to my personal web site.

The rewrite section worked weirdly to me at first when creating the release configs, errors and sections not showing at all. This is how i solved it.
Microsoft (R) Build Engine version 12.0.31101.0
Microsoft .NET Framework, version 4.0.30319.0
Edit After messing about with this i realized that having the rewrite tag on a server that does not have the rewrite plugin make the webserver return an error. I want different configurations on server and local development machine so the fix is:
The un-transformed web.config only needs a <system.webServer> tag and in the web.config.release for a basic canonical host name rule
<configuration>
<system.webServer>
<rewrite xdt:Transform="Insert">
<rules>
<rule name="CanonicalHostNameRule" xdt:Transform="Insert">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www\.host\.com$" negate="true" />
</conditions>
<action type="Redirect" url="http://www.host.com/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
The action didn't need a name at all but the rewrite tag needs the xdt:Transform="Insert"
Obviously if you want it on your local machine as well, it would need an update instead.

It is possible to transform the rewrite section of system.webServer. I was initially having the same problem and realized that I had inadvertently placed the rewrite node incorrectly under system.web. While this does not look like your problem based on the limited snippet that you provided, I would still suspect that your issue is related to node placement in the transform file.
Here is what my Web.Debug.config looks like (and this version is writing the correct Web.config on a debug build):
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an atrribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<system.web>
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
<system.webServer>
<rewrite xdt:Transform="Replace">
<rules>
<clear/>
<rule name="Canonical Hostname">
<!-- Note that I have stripped out the actual content of my rules for the purposes of posting here... -->
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

A trick I use is give the action a name
then in my transform just add xdt:Transform="SetAttributes" xdt:Locator="Match(name)" like the following
<system.webServer>
<rewrite>
<rules>
<rule name="RedirecttoWWW" enabled="true" >
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^www\.([.a-zA-Z0-9]+)$" />
</conditions>
<action name="AddWWW" type="Redirect" url="http://www.{HTTP_HOST}/{R:0}" appendQueryString="true" redirectType="Permanent" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</rule>
</rules>
</rewrite>
The above example is to add www to all requests
-------UPDATE-----
just an update adding name to the action will not work as wanted so I updated the code as the following
<system.webServer>
<rule name="RedirecttoWWW" enabled="true" xdt:Transform="RemoveAll" xdt:Locator="Match(name)" >
</rule>
<rule name="RedirecttoWWW" enabled="true" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" >
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^www\.([.a-zA-Z0-9]+)$" />
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}/{R:0}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>

Related

Redirect Rule in web.config not including folder path

I'm working on a client application where they have a nested HTML-only app in a rooted subfolder of an otherwise ASP.NET application.
The domain name is changing for the HTML app only, and I need to be sure that the requests are routed to the new domain name. So, using the rewriteRules sounds like a perfect tool for this, but I'm doing something wrong and need another set of eyes.
The original URL is something like this:
https://example.com/folder1/folder2/app/index.html
The new domain is on an entirely different server and I want all requests from the app folder to go to the new domain name. Here is an example:
https://newdomain.com/folder1/folder2/app/index.html
Unfortunately, I'm doing something wrong that's probably obvious... I keep getting this URL in the redirect.
https://newdomain.com/index.html
Here is the web.config showing what I tried. It's in the app folder.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
<system.webServer>
<rewrite>
<rules>
<rule name="RedirectHtmlApp" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^(www\.)?example\.com$" />
</conditions>
<action type="Redirect" url="https://newdomain.com/{R:0}" redirectType="Permanent" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
{R:0} and {R:1} both return index.html.
What is passed to {R:0} is relative. So if your web.config is in /folder1/folder2/app/{here} then "folder1/folder2/app/" are not passed along. If your web.config rule is in the root of the site-app above /folder1, then I am wrong, but if I am right, then you just need to include the path to the root of the app at the destination also. Given what you have above,
<action type="Redirect"
url="https://newdomain.com/folder1/folder2/app/{R:0}"
redirectType="Permanent" appendQueryString="true" />

Hosting Symfony 3 inside subdirectory on IIS

I have a really harsh time trying to get Symfony 3 app work on IIS as website subdirectory.
Structure on IIS :
Application is called pfc and its poiting to directory pfc/web, (IIS is hiding root, because folder name is same as app)
This is web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<defaultDocument>
<files>
<add value="app_dev.php" />
</files>
</defaultDocument>
<rewrite>
<rules>
<clear />
<rule name="StaticFiles" stopProcessing="true">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile"/>
</conditions>
<action type="Rewrite" url="{R:0}" logRewrittenUrl="true" />
</rule>
<rule name="Symfony 3" enabled="true" stopProcessing="true">
<match url=".?" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="./app_dev.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Entering dev.erp.loc/Test2/pfc ends up with:
like Symfony thinks of itself as a root application, which is not.
My best shoot was to use router.request_context.base_url, but it looks like it worked only in S2.
Now im stuck on something i can call half-way solution
By comment rewrite section in web.config i was correctly redirected to Identity Server, but after log in i get :
In order to fix it, i needed to uncomment rewrite section, to make routing work again, but it works only for browser, leaving it in this state will cause "no route found" in anther browser.
It would be nice to fix subdirectory routing in parameters.yml, which I fill anyway in deploy script, but if there is no other way I can edit web.config too.
Recently I needed to take care of similar issue and as side effect I solved this "problem". My URL without trailing slash is correct. The issue was that Chrome couldn't create canonical url form and made request to endpoint that Symfony don't need to interpret

Trouble using Silex framework on IIS

I am trying to configure the silex framework and just get an example application working. I am using an IIS server version 7.5 to do so. On the following website it gives me a sample web.config file I should be using. The file is as follows:
<?xml version="1.0"?>
<configuration>
<system.webServer>
<defaultDocument>
<files>
<clear />
<add value="index.php" />
</files>
</defaultDocument>
<rewrite>
<rules>
<rule name="Silex Front Controller" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
The problem is when trying to navigate to the website I just get the error:
The requested page cannot be accessed because the related
configuration data for the page is invalid.
So essentially IIS says the file is incorrect but I don't have much experience with these files so I don't know if there is a problem. Maybe the file is outdated and the newer doesn't work with newer versions of IIS. There is nothing in the server logs. Anyone come across this problem before?
Turns out I just needed to install the rewrite module for IIS at the following link:
http://www.iis.net/learn/extensions/url-rewrite-module/using-the-url-rewrite-module

With a web.config transform, how do you inject a canonical url rule at the top?

Within an ASP.Net project, for the release build's Web.Config (using a Web.Release.Config transform file), how do you inject a canonical url rule in the rewrite section?
Below is an example that worked for me, you have to use an XPath selector in order to inject your rule into the proper position via the xdt:Transform property.
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<rewrite>
<rules>
<rule name="CanonicalHostNameRule1" enabled="true" stopProcessing="true"
xdt:Transform="InsertBefore(/configuration/system.webServer/rewrite/rules/rule[position() = 1])"
>
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^www\.yoursite\.com$" />
</conditions>
<action type="Redirect" url="http://www.yoursite.com/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
You can do some other interesting replacements using xpath statements as well. I hope the above example is helpful as StackOverflow is generally where I look first for this type of thing these days.

IIS 7 URL rewrite module web.config section c#

We are using IIS7 URL rewrite module with asp.net C#, all of the URLs are configured and written directly into web.config:
<system.webServer>
<!-- ... -->
<rewrite>
<rules>
<clear />
<rule name="Category URL" stopProcessing="true">
<match url="somepage.aspx" ignoreCase="false"/>
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{QUERY_STRING}" pattern="REDIRECTION=true"
ignoreCase="false"/>
<add input="{QUERY_STRING}" pattern="categoryid=([^&]*)"/>
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}/browsing/categorylanding.aspx?navcategoryid={C:1}"/>
</rule>
</rules>
</rewrite>
</system.webServer>
I need to move this to a section so that I can have seperate rules for QA, DEV and Production, what would be the "type that i would define in the section?
<configSections>
<section name="IISURLRewriteSection" type="???"/>
</configSections>
Will the IIS automatically pick up these settings once moved outside from web.config to another custom config file?
We resorted to writing our own HTTPModule since from debugging point of view as well any issues that would arise at IIS level would have to have the Operations team involved - just following a process defined in our org :)
The best solution, imho, would be to move the configuration details into external files, which you can then swap out per-environment.
This is pretty easy to do using the method described in Moving IIS7 url rewrite section out of the web.config file, where you would have something like this in your Web.config file:
<system.webServer>
<rewrite configSource="rewrite.config"/>
</system.webServer>
Then you can store the environment specific stuff in a separate file, rewrite.config, looking something like this:
<rewrite>
<rules>
<clear />
<rule name="Category URL" stopProcessing="true">
<!-- ... --->
</rule>
</rules>
</rewrite>

Resources