IIS URL Rewrite: Add trailing slash except for .html and .aspx - asp.net

Adding a trailing slash to all URLs through IIS URL Rewrite Module is widely spread, but how do I add exceptions for URLs that ends with .html and .aspx?
Today I have this:
<rule name="Add trailing slash" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<!-- Doesn't seem to be working -->
<!--<add input="{REQUEST_URI}" pattern="(.*?).html$" negate="true" />-->
<!--<add input="{REQUEST_URI}" pattern="(.*?).aspx$" negate="true" />-->
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>

If you want something done right, you've got to do it yourself, obviously...
Here is the solution to my question:
<rule name="Add trailing slash" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" pattern="(.*?)\.html$" negate="true" />
<add input="{REQUEST_FILENAME}" pattern="(.*?)\.aspx$" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>
Update: I blogged about this in more detail.

Varying the other answers, I used this so I wouldn't have to specify a list of file extensions:
<!-- Ensure trailing slash -->
<rule name="Add trailing slash" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" pattern="(.*?)\.[a-zA-Z]{1,4}$" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>

We add multiple extensions like this:
<add input="{URL}" negate="true" pattern="((.+).(jpg|ico|gif|js|png|htm|css|html))" ignoreCase="true" />

To prevent all files from having a slash added, I changed the match rule to this:
<match url="^([^.]*[^/])$" />
That applies the rule only to paths that include any number of non-dot characters that does not end in a slash. So any path that includes a dot (e.g. xxx.html, xxx.aspx, etc.) would be excluded without needing any additional negation rule.
Looking for the presence of a dot in the match rule allowed me to completely remove the condition rules that use match types IsFile and IsDirectory. Those match types are only allowed in distributed rules (web.config), not in the global rules (applicationHost.config), so I had been forced to replicate this rule for every site instead of applying it to all sites using a global rule. By modifying the regex in the match rule to exclude files and removing the IsFile and IsDirectory conditions, I was able to create a global rule instead of having multiple distributed rules.

<conditions>
<add input="{URL}" pattern="(.*)\.(.*)[a-z]$" negate="true" />
<add input="{URL}" pattern="(.*)\.(.*)[0-9]$" negate="true" />
</conditions>
except for .html and .aspx and .woff2

This almost worked for me. I had to change it to
<add input="{URL}" pattern="(.*?)\.html$" negate="true" />
<add input="{URL}" pattern="(.*?)\.aspx$" negate="true" />
Otherwise thanks for this!

To prevent POST, DELETE and other REST method calls without a trailing slash from erroneously becoming a GET request through the redirect consider adding the following condition:
<add input="{REQUEST_METHOD}" matchType="Pattern" pattern="GET" ignoreCase="true" />

You can try this:
<conditions>
<add input="{URL}" pattern="(.*)\.(.*)$" negate="true" />
</conditions>

Related

IIS manager url rules for similar urls

I have two urls: http://...../m?PageView=View1&Language=English&AName=AAA and another http://...../m?PageView=View2TName=T1&AName=XYZ. Both this urls are for separate section/functionality. But as the number and pattern of parameters are same one url work and another does not.
I want to write url redirect and rewrite rules for two similar urls. I have written first rule as below.
<rule name="RedirectUserFriendlyURL12" stopProcessing="true">
<match url="^m/$" />
<conditions>
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern="^View=([^=&]+)&Language=([^=&]+)&AName=([^=&]+)$" />
</conditions>
<action type="Redirect" url="m/{C:1}/{C:2}/{C:3}" appendQueryString="false" />
</rule>
<rule name="RewriteUserFriendlyURL12" stopProcessing="true">
<match url="^m/([^/]+)/([^/]+)/([^/]+)/?$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="m?View={R:1}&Language={R:2}&AName={R:3}" />
</rule>
and another url has same number of parameters but different name as below. Here is 2nd rule.
<rule name="RedirectUserFriendlyURL12" stopProcessing="true">
<match url="^m/$" />
<conditions>
<add input="{REQUEST_METHOD}" pattern="^POST$" negate="true" />
<add input="{QUERY_STRING}" pattern="^View=([^=&]+)&TName=([^=&]+)&AName=([^=&]+)$" />
</conditions>
<action type="Redirect" url="m/{C:1}/{C:2}/{C:3}" appendQueryString="false" />
</rule>
<rule name="RewriteUserFriendlyURL12" stopProcessing="true">
<match url="^m/([^/]+)/([^/]+)/([^/]+)/?$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="m?View={R:1}&TName={R:2}&AName={R:3}" />
</rule>
When I have above two rules in web.config, one url works properly i.e. rediected and rewritten But another one does not work.
How can I differentiate both the rules so it works for both the urls.
I solved my issue. I have kept only one rule only, first one.
But in my controller code actually I had to map parameters accordingly. Means not TName parameter value I have to access, I have to access language parameter only for View-2 also, as value of TName is getting passed in Language parameter when rules get apply.
I could have use two rules but then I would have to change the redirect target URL. Like redirect
^View=([^=&]+)&TName=([^=&]+)&AName=([^=&]+)$ to m/{C:1}/tname/{C:2}/{C:3}
Then rewrite back from
^m/([^/]+)/tname/([^/]+)/([^/]+)/?$ to m?View={R:1}&TName={R:2}&AName={R:3}.
But I didn't wanted to have this above thing.

IIS rewrite - add '.html' to any URL's that don't have an extension

I'm trying to setup an IIS rewrite rule to add '.html' to URL's that don't have an extension, eg:
Original URL: www.domain.com/page
Rewrite to: www.domain.com/page.html
And I want to ignore any URL's that have an extension (eg. if they are images or other files)
Does anybody know the rule that I would need to set this up?
I worked this out myself by modifying a rule that I had on another website:
<rule name="rewrite directories to html" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" pattern="(.*?)\.[a-zA-Z]{1,4}$" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}.html" />
</rule>

Conflicting URL rewrite rules

I have two URL rewrite rules. Individually they work perfectly, but when both are turned on, they are conflicting.
The first is in my root dir web.config, takes all requests to files in /seo/ and serves them by requests in the root of the website.
<rule name="RewriteToFile">
<match url="^(?!seo/)(.*)" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="seo/{R:1}" />
</rule>
The next one is in the web.config in a sub directory called /blog (it's a Wordpress blog).
<rule name="wordpress" patternSyntax="Wildcard">
<match url="*"/>
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
</conditions>
<action type="Rewrite" url="index.php"/>
</rule>
Individually turned on, they work fine, but if both of them are on, the blog will only serve 403's...
Is there a way to enable both of these rules?

How would one rewrite the url to remove the aspx extension and also redirect a trailing slash?

I want to remove the aspx extension for clean urls, and also redirect when a trailing slash is used.
In my web.config file:
<!-- Rewrite, adding extension -->
<rule name="add aspx">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" negate="true" pattern="\.axd$" />
</conditions>
<action type="Rewrite" url="{R:1}.aspx" />
</rule>
<!-- Removes trailing slash after rewrite -->
<rule name="remove trailing slash after rewrite" stopProcessing="true">
<match url="(.*)/.aspx$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}" />
</rule>
So, basically if one requests the url "mysite/mypage", this will have the aspx extension added on and work okay, and when one requests "mysite/mypage/", they get redirected to "mysite/mypage".
My solution seems to work, but is there a more efficient way to do it with just a rewrite and not a redirect?
I didn't realize that order matters, so I did the following: first redirect the trailing slash, then do the rewrite.
<rule name="Remove trailing slash" stopProcessing="true">
<match url="(.*)/$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}" />
</rule>
<rule name="Add aspx">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" negate="true" pattern="\.axd$" />
</conditions>
<action type="Rewrite" url="{R:1}.aspx" />
</rule>
This seems to be the best way, unless someone knows a better one.

Remove ASPX FILE Extention in Web.config But Negate Rewrite if URL Contains Period

All right, so by now most of us probably use the standard rule below for remove the aspx extention in your urls.
<rule name="Remove">
<!--Removes the .aspx extension for all pages.-->
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}.aspx" />
</rule>
However I would like to modify the rule to prevent the write rule from catching any url with a period in it.
That way if someone tries to type in http://www.domain.com/picture.jpg
The rule doesn't catch it.
Luckily the IsFile and IsDirectory conditions prevent actual files from being hit by the rule but whenever I have a case where someone types in a file that doesn't exist on the server then the rule catches it and asp.net does something like this:
http://www.domain.com/404error.aspx?aspxerrorpath=/picture.jpg.aspx
Id like it to not pass through the rule when there is a file not found.
Basically I just need to be able to add a condition that negates whenever a period is found in the url after the domain name. I'm assuming some sort of REGEX will work. I can't seem to get it working right though.
I was able to come up with the following solution.
<rule name="RewriteASPX" stopProcessing="true" enabled="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_FILENAME}.aspx" matchType="IsFile" />
</conditions>
<action type="Rewrite" url="{R:1}.aspx" />
</rule>

Resources