Dots in URL causes 404 with ASP.NET mvc and IIS - asp.net-mvc

I have a project that requires my URLs have dots in the path. For example I may have a URL such as www.example.com/people/michael.phelps
URLs with the dot generate a 404. My routing is fine. If I pass in michaelphelps, without the dot, then everything works. If I add the dot I get a 404 error. The sample site is running on Windows 7 with IIS8 Express. URLScan is not running.
I tried adding the following to my web.config:
<security>
<requestFiltering allowDoubleEscaping="true"/>
</security>
Unfortunately that didn't make a difference. I just receive a 404.0 Not Found error.
This is a MVC4 project but I don't think that's relevant. My routing works fine and the parameters I expect are there, until they include a dot.
What do I need to configure so I can have dots in my URL?

I got this working by editing my site's HTTP handlers. For my needs this works well and resolves my issue.
I simply added a new HTTP handler that looks for specific path criteria. If the request matches it is correctly sent to .NET for processing. I'm much happier with this solution that the URLRewrite hack or enabling RAMMFAR.
For example to have .NET process the URL www.example.com/people/michael.phelps add the following line to your site's web.config within the system.webServer / handlers element:
<add name="ApiURIs-ISAPI-Integrated-4.0"
path="/people/*"
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
Edit
There are other posts suggesting that the solution to this issue is RAMMFAR or RunAllManagedModulesForAllRequests. Enabling this option will enable all managed modules for all requests. That means static files such as images, PDFs and everything else will be processed by .NET when they don't need to be. This options is best left off unless you have a specific case for it.

After some poking around I found that relaxedUrlToFileSystemMapping did not work at all for me, what worked in my case was setting RAMMFAR to true, the same is valid for (.net 4.0 + mvc3) and (.net 4.5 + mvc4).
<system.webserver>
<modules runAllManagedModulesForAllRequests="true">
Be aware when setting RAMMFAR true Hanselman post about RAMMFAR and performance

I believe you have to set the property relaxedUrlToFileSystemMapping in your web.config. Haack wrote an article about this a little while ago (and there are some other SO posts asking the same types of question)
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
Edit
From the comments below, later versions of .NET / IIS may require this to be in the system.WebServer element.
<system.webServer>
<httpRuntime relaxedUrlToFileSystemMapping="true" />

I got stuck on this issue for a long time following all the different remedies without avail.
I noticed that when adding a forward slash [/] to the end of the URL containing the dots [.], it did not throw a 404 error and it actually worked.
I finally solved the issue using a URL rewriter like IIS URL Rewrite to watch for a particular pattern and append the training slash.
My URL looks like this: /Contact/~firstname.lastname so my pattern is simply: /Contact/~(.*[^/])$
I got this idea from Scott Forsyth, see link below:
http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path

Just add this section to Web.config, and all requests to the route/{*pathInfo} will be handled by the specified handler, even when there are dots in pathInfo. (taken from ServiceStack MVC Host Web.config example and this answer https://stackoverflow.com/a/12151501/801189)
This should work for both IIS 6 & 7. You could assign specific handlers to different paths after the 'route' by modifying path="*" in 'add' elements
<location path="route">
<system.web>
<httpHandlers>
<add path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" />
</httpHandlers>
</system.web>
<!-- Required for IIS 7.0 -->
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<add name="ApiURIs-ISAPI-Integrated-4.0" path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
</location>

MVC 5.0 Workaround.
Many of the suggested answers doesn't seem to work in MVC 5.0.
As the 404 dot problem in the last section can be solved by closing that section with a trailing slash, here's the little trick I use, clean and simple.
While keeping a convenient placeholder in your view:
#Html.ActionLink("Change your Town", "Manage", "GeoData", new { id = User.Identity.Name }, null)
add a little jquery/javascript to get the job done:
<script>
$('a:contains("Change your Town")').on("click", function (event) {
event.preventDefault();
window.location.href = '#Url.Action("Manage", "GeoData", new { id = User.Identity.Name })' + "/";
});</script>
please note the trailing slash, that is responsible for changing
http://localhost:51003/GeoData/Manage/user#foo.com
into
http://localhost:51003/GeoData/Manage/user#foo.com/

Super easy answer for those that only have this on one webpage. Edit your actionlink and a + "/" on the end of it.
#Html.ActionLink("Edit", "Edit", new { id = item.name + "/" }) |

Depending on how important it is for you to keep your URI without querystrings, you can also just pass the value with dots as part of the querystring, not the URI.
E.g. www.example.com/people?name=michael.phelps will work, without having to change any settings or anything.
You lose the elegance of having a clean URI, but this solution does not require changing or adding any settings or handlers.

You might want to think about using dashes instead of periods.
In Pro ASP MVC 3 Framework they suggest this about making friendly URLs:
Avoid symbols, codes, and character sequences. If you want a word
separator, use a dash (/my-great-article). Underscores are unfriendly,
and URL-encoded spaces are bizarre (/my+great+article) or disgusting
(/my%20great%20article).
It also mentions that URLs should be be easy to read and change for humans. Maybe a reason to think about using a dash instead of a dot also comes from the same book:
Don't use file name extensions for HTML pages (.aspx or .mvc), but do use them for specialized file types (.jpg, .pdf, .zip, etc). Web browsers don't care about file name extensions if you set the MIME type appropriately, but humans still expect PDF files to end with .pdf
So while a period is still readable to humans (though less readable than dashes, IMO), it might still be a bit confusing/misleading depending on what comes after the period. What if someone has a last name of zip? Then the URL will be /John.zip instead of /John-zip, something that can be misleading even to the developer that wrote the application.

Would it be possible to change your URL structure?
For what I was working on I tried a route for
url: "Download/{fileName}"
but it failed with anything that had a . in it.
I switched the route to
routes.MapRoute(
name: "Download",
url: "{fileName}/Download",
defaults: new { controller = "Home", action = "Download", }
);
Now I can put in localhost:xxxxx/File1.doc/Download and it works fine.
My helpers in the view also picked up on it
#Html.ActionLink("click here", "Download", new { fileName = "File1.doc"})
that makes a link to the localhost:xxxxx/File1.doc/Download format as well.
Maybe you could put an unneeded word like "/view" or action on the end of your route so your property can end with a trailing / something like /mike.smith/view

As solution could be also considering encoding to a format which doesn't contain symbol., as base64.
In js should be added
btoa(parameter);
In controller
byte[] bytes = Convert.FromBase64String(parameter);
string parameter= Encoding.UTF8.GetString(bytes);

It's as simple as changing path="." to path="". Just remove the dot in the path for ExensionlessUrlHandler-Integrated-4.0 in web.config.
Here's a nice article https://weblog.west-wind.com/posts/2015/Nov/13/Serving-URLs-with-File-Extensions-in-an-ASPNET-MVC-Application

Tried all the solutions above but none of them worked for me. What did work was I uninstalling .NET versions > 4.5, including all its multilingual versions; Eventually I added newer (English only) versions piece by piece. Right now versions installed on my system is this:
2.0
3.0
3.5 4
4.5
4.5.1
4.5.2
4.6
4.6.1
And its still working at this point. I'm afraid to install 4.6.2 because it might mess everything up.
So I could only speculate that either 4.6.2 or all those non-English versions were messing up my configuration.

I was able to solve my particular version of this problem (had to make /customer.html route to /customer, trailing slashes not allowed) using the solution at https://stackoverflow.com/a/13082446/1454265, and substituting path="*.html".

Add URL Rewrite rule to Web.config archive. You need to have the URL Rewrite module already installed in IIS. Use the following rewrite rule as inspiration for your own.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Add trailing slash for some URLs" stopProcessing="true">
<match url="^(.*(\.).+[^\/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Also, (related) check the order of your handler mappings. We had a .ashx with a .svc (e.g. /foo.asmx/bar.svc/path) in the path after it. The .svc mapping was first so 404 for the .svc path which matched before the .asmx.
Havn't thought too much but maybe url encodeing the path would take care of this.

This is the best solution I have found for the error 404 on IIS 7.5 and .NET Framework 4.5 environment, and without using: runAllManagedModulesForAllRequests="true".
I followed this thread: https://forums.asp.net/t/2070064.aspx?Web+API+2+URL+routing+404+error+on+IIS+7+5+IIS+Express+works+fine and I have modified my web.config accordingly, and now the MVC web app works well on IIS 7.5 and .NET Framework 4.5 environment.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebApplication1.Controllers
{
[RoutePrefix("File")]
[Route("{action=index}")]
public class FileController : Controller
{
// GET: File
public ActionResult Index()
{
return View();
}
[AllowAnonymous]
[Route("Image/{extension?}/{filename}")]
public ActionResult Image(string extension, string filename)
{
var dir = Server.MapPath("/app_data/images");
var path = Path.Combine(dir, filename+"."+ (extension!=null? extension:"jpg"));
// var extension = filename.Substring(0,filename.LastIndexOf("."));
return base.File(path, "image/jpeg");
}
}
}

Related

HTTP 413 - Request Entity Too Large cheat sheet

I am trying to upload a large file to my ASP.net core/ASP.net mvc site, but keep on encountering HTTP 413 - request entity too large. Even when I try to update web.config, other things still break.
Does anyone have a cheat sheet for dealing with this?
I created an asp.net mvc application and tried to test it.
Often we only pay attention to the uploadReadAheadSize setting, but tests have proved that this cannot completely solve the problem, and there are other configurations that need to be configured. (Added based on Jack's answer)
In addition to setting the uploadReadAheadSize value larger, there are also maxAllowedContentLength and maxRequestLength. You need to modify all these three values, otherwise the 413 or Maximum request length exceeded error will still be displayed.
In my test results, the application can upload any type of file within 1GB.
This works for me. Set it in your web.config under the configuration section:
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="999999999" />
</requestFiltering>
</security>
</system.webServer>
Here is my cheat sheet:
The max file size limit coming through from IIS is specified through the UploadReadAhaead parameter, which can be specified in web.config as so. In this case, the maximum is set to 1000485760 bytes
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpErrors errorMode="Detailed"></httpErrors>
<serverRuntime uploadReadAheadSize="1000485760" />
<httpErrors errorMode="Detailed" />
<asp scriptErrorSentToBrowser="true"/>
</system.webServer>
<system.web>
<customErrors mode="Off"/>
<compilation debug="true"/>
</system.web>
</configuration>
This is grand, as long as this specifier actually works. You might need a different solution, say, if you are hosting locally with something other than IIS (like kestrel, or even IIS express.)
Sometimes this configuration section is locked as well, in which case it can be unlocked using the following command (run cmd as admin):
%windir%\system32\inetsrv\appcmd.exe unlock config -section:system.webServer/serverRuntime
This is also something to consider when setting up prod. In some cases, your configuration within web.config within your code for the uploadReadAheadSize can conflict with whatever is specified in your prod instance. For me, I ended up getting rid of my configuration within source control, and instead, set the uploadReadAhead value for prod during environment set up. I did this by running the command (in cmd as admin):
appcmd set config "https://example.com" /section:system.webserver/serverruntime /uploadreadaheadsize:500048576 /commit:apphost
appcmd set config "http://example.com" /section:system.webserver/serverruntime /uploadreadaheadsize:500048576 /commit:apphost
I also set uploadReadAheadSize within C:\inetpub\wwwroot\web.config on the prod server as well, so it looks something like:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<serverRuntime uploadReadAheadSize="500485760" />
<!--If this line breaks, unlock the config by opening cmd as admin and running %windir%\system32\inetsrv\appcmd.exe unlock config -section:system.webServer/serverRuntime-->
</system.webServer>
</configuration>
This can also be set as per this screenshot:
[![enter image description here][1]][1]
Now that you've set this up, it's still entirely possible that your application breaks, giving you a 413 because even though IIS may be set up correctly, there are also upload limits within the .net core ecosystem which can throw an HTTP 414 error when handling large files. This is something I found out [here][2]
The TLDR of this is that you want to have the following code within your startup.cs -> configureServices()
services.Configure<IISServerOptions>(options => {
options.MaxRequestBodySize = int.MaxValue;
});
services.Configure<FormOptions>(x =>
{
x.ValueLengthLimit = int.MaxValue;
x.MultipartBodyLengthLimit = int.MaxValue;
x.BufferBodyLengthLimit = int.MaxValue;
x.MultipartBoundaryLengthLimit = int.MaxValue;
});
Note that there is code in there for if you are hosting for kestrel rather than IIS, also
[1]: https://i.stack.imgur.com/yLHQQ.png
[2]: https://github.com/dotnet/aspnetcore/issues/20369#issuecomment-607057822

HTTP Error 404.0 - Not Found on action in controller. MVC [duplicate]

I have a project that requires my URLs have dots in the path. For example I may have a URL such as www.example.com/people/michael.phelps
URLs with the dot generate a 404. My routing is fine. If I pass in michaelphelps, without the dot, then everything works. If I add the dot I get a 404 error. The sample site is running on Windows 7 with IIS8 Express. URLScan is not running.
I tried adding the following to my web.config:
<security>
<requestFiltering allowDoubleEscaping="true"/>
</security>
Unfortunately that didn't make a difference. I just receive a 404.0 Not Found error.
This is a MVC4 project but I don't think that's relevant. My routing works fine and the parameters I expect are there, until they include a dot.
What do I need to configure so I can have dots in my URL?
I got this working by editing my site's HTTP handlers. For my needs this works well and resolves my issue.
I simply added a new HTTP handler that looks for specific path criteria. If the request matches it is correctly sent to .NET for processing. I'm much happier with this solution that the URLRewrite hack or enabling RAMMFAR.
For example to have .NET process the URL www.example.com/people/michael.phelps add the following line to your site's web.config within the system.webServer / handlers element:
<add name="ApiURIs-ISAPI-Integrated-4.0"
path="/people/*"
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
Edit
There are other posts suggesting that the solution to this issue is RAMMFAR or RunAllManagedModulesForAllRequests. Enabling this option will enable all managed modules for all requests. That means static files such as images, PDFs and everything else will be processed by .NET when they don't need to be. This options is best left off unless you have a specific case for it.
After some poking around I found that relaxedUrlToFileSystemMapping did not work at all for me, what worked in my case was setting RAMMFAR to true, the same is valid for (.net 4.0 + mvc3) and (.net 4.5 + mvc4).
<system.webserver>
<modules runAllManagedModulesForAllRequests="true">
Be aware when setting RAMMFAR true Hanselman post about RAMMFAR and performance
I believe you have to set the property relaxedUrlToFileSystemMapping in your web.config. Haack wrote an article about this a little while ago (and there are some other SO posts asking the same types of question)
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
Edit
From the comments below, later versions of .NET / IIS may require this to be in the system.WebServer element.
<system.webServer>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
I got stuck on this issue for a long time following all the different remedies without avail.
I noticed that when adding a forward slash [/] to the end of the URL containing the dots [.], it did not throw a 404 error and it actually worked.
I finally solved the issue using a URL rewriter like IIS URL Rewrite to watch for a particular pattern and append the training slash.
My URL looks like this: /Contact/~firstname.lastname so my pattern is simply: /Contact/~(.*[^/])$
I got this idea from Scott Forsyth, see link below:
http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path
Just add this section to Web.config, and all requests to the route/{*pathInfo} will be handled by the specified handler, even when there are dots in pathInfo. (taken from ServiceStack MVC Host Web.config example and this answer https://stackoverflow.com/a/12151501/801189)
This should work for both IIS 6 & 7. You could assign specific handlers to different paths after the 'route' by modifying path="*" in 'add' elements
<location path="route">
<system.web>
<httpHandlers>
<add path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" />
</httpHandlers>
</system.web>
<!-- Required for IIS 7.0 -->
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<add name="ApiURIs-ISAPI-Integrated-4.0" path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
</location>
MVC 5.0 Workaround.
Many of the suggested answers doesn't seem to work in MVC 5.0.
As the 404 dot problem in the last section can be solved by closing that section with a trailing slash, here's the little trick I use, clean and simple.
While keeping a convenient placeholder in your view:
#Html.ActionLink("Change your Town", "Manage", "GeoData", new { id = User.Identity.Name }, null)
add a little jquery/javascript to get the job done:
<script>
$('a:contains("Change your Town")').on("click", function (event) {
event.preventDefault();
window.location.href = '#Url.Action("Manage", "GeoData", new { id = User.Identity.Name })' + "/";
});</script>
please note the trailing slash, that is responsible for changing
http://localhost:51003/GeoData/Manage/user#foo.com
into
http://localhost:51003/GeoData/Manage/user#foo.com/
Super easy answer for those that only have this on one webpage. Edit your actionlink and a + "/" on the end of it.
#Html.ActionLink("Edit", "Edit", new { id = item.name + "/" }) |
Depending on how important it is for you to keep your URI without querystrings, you can also just pass the value with dots as part of the querystring, not the URI.
E.g. www.example.com/people?name=michael.phelps will work, without having to change any settings or anything.
You lose the elegance of having a clean URI, but this solution does not require changing or adding any settings or handlers.
You might want to think about using dashes instead of periods.
In Pro ASP MVC 3 Framework they suggest this about making friendly URLs:
Avoid symbols, codes, and character sequences. If you want a word
separator, use a dash (/my-great-article). Underscores are unfriendly,
and URL-encoded spaces are bizarre (/my+great+article) or disgusting
(/my%20great%20article).
It also mentions that URLs should be be easy to read and change for humans. Maybe a reason to think about using a dash instead of a dot also comes from the same book:
Don't use file name extensions for HTML pages (.aspx or .mvc), but do use them for specialized file types (.jpg, .pdf, .zip, etc). Web browsers don't care about file name extensions if you set the MIME type appropriately, but humans still expect PDF files to end with .pdf
So while a period is still readable to humans (though less readable than dashes, IMO), it might still be a bit confusing/misleading depending on what comes after the period. What if someone has a last name of zip? Then the URL will be /John.zip instead of /John-zip, something that can be misleading even to the developer that wrote the application.
Would it be possible to change your URL structure?
For what I was working on I tried a route for
url: "Download/{fileName}"
but it failed with anything that had a . in it.
I switched the route to
routes.MapRoute(
name: "Download",
url: "{fileName}/Download",
defaults: new { controller = "Home", action = "Download", }
);
Now I can put in localhost:xxxxx/File1.doc/Download and it works fine.
My helpers in the view also picked up on it
#Html.ActionLink("click here", "Download", new { fileName = "File1.doc"})
that makes a link to the localhost:xxxxx/File1.doc/Download format as well.
Maybe you could put an unneeded word like "/view" or action on the end of your route so your property can end with a trailing / something like /mike.smith/view
As solution could be also considering encoding to a format which doesn't contain symbol., as base64.
In js should be added
btoa(parameter);
In controller
byte[] bytes = Convert.FromBase64String(parameter);
string parameter= Encoding.UTF8.GetString(bytes);
It's as simple as changing path="." to path="". Just remove the dot in the path for ExensionlessUrlHandler-Integrated-4.0 in web.config.
Here's a nice article https://weblog.west-wind.com/posts/2015/Nov/13/Serving-URLs-with-File-Extensions-in-an-ASPNET-MVC-Application
Tried all the solutions above but none of them worked for me. What did work was I uninstalling .NET versions > 4.5, including all its multilingual versions; Eventually I added newer (English only) versions piece by piece. Right now versions installed on my system is this:
2.0
3.0
3.5 4
4.5
4.5.1
4.5.2
4.6
4.6.1
And its still working at this point. I'm afraid to install 4.6.2 because it might mess everything up.
So I could only speculate that either 4.6.2 or all those non-English versions were messing up my configuration.
I was able to solve my particular version of this problem (had to make /customer.html route to /customer, trailing slashes not allowed) using the solution at https://stackoverflow.com/a/13082446/1454265, and substituting path="*.html".
Add URL Rewrite rule to Web.config archive. You need to have the URL Rewrite module already installed in IIS. Use the following rewrite rule as inspiration for your own.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Add trailing slash for some URLs" stopProcessing="true">
<match url="^(.*(\.).+[^\/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Also, (related) check the order of your handler mappings. We had a .ashx with a .svc (e.g. /foo.asmx/bar.svc/path) in the path after it. The .svc mapping was first so 404 for the .svc path which matched before the .asmx.
Havn't thought too much but maybe url encodeing the path would take care of this.
This is the best solution I have found for the error 404 on IIS 7.5 and .NET Framework 4.5 environment, and without using: runAllManagedModulesForAllRequests="true".
I followed this thread: https://forums.asp.net/t/2070064.aspx?Web+API+2+URL+routing+404+error+on+IIS+7+5+IIS+Express+works+fine and I have modified my web.config accordingly, and now the MVC web app works well on IIS 7.5 and .NET Framework 4.5 environment.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebApplication1.Controllers
{
[RoutePrefix("File")]
[Route("{action=index}")]
public class FileController : Controller
{
// GET: File
public ActionResult Index()
{
return View();
}
[AllowAnonymous]
[Route("Image/{extension?}/{filename}")]
public ActionResult Image(string extension, string filename)
{
var dir = Server.MapPath("/app_data/images");
var path = Path.Combine(dir, filename+"."+ (extension!=null? extension:"jpg"));
// var extension = filename.Substring(0,filename.LastIndexOf("."));
return base.File(path, "image/jpeg");
}
}
}

Routing static files in ASP.NET MVC 3 like robots.txt

I would like to have the following link "http://mywebsite.com/robots.txt" linked to a static file ~/Content/robots.txt.
How can I do this?
Thanks,
Merijn
Adding a route like this should do the trick. This way any static .txt file like robots.txt can be served.
routes.IgnoreRoute("{resource}.txt");
You could install Url Rewrite module:
http://www.iis.net/downloads/microsoft/url-rewrite
Remember that this module works on IIS and not on Cassini/IIS Express.
And add following rule to your web.config to section <system.webServer>
<rewrite>
<rules>
<rule name="robots" stopProcessing="true">
<match url="robots.txt" />
<action type="Rewrite" url="/Content/robots.txt" />
</rule>
</rules>
</rewrite>
I checked it on new MVC 3 .NET project and both url responses with the same file:
mywebsite.com/robots.txt
mywebsite.com/Content/robots.txt
You can setup routing request for disk files. By default the routing system checks to see if the url matches the disk file before evaluating the application's routes. If there is a match the disk file is served and routes are not used. However this can be reveresed so routes are looked at before disk files are checked by setting the RouteExisitingFiles property of RouteCollection to true. Place this statement close to the top of the RegisterRoutes method - this just seems to be convention for mvc apps. Then you define a route that for the disk files. Be aware when doing this that there can some unforseen effects because the riute could natch other kinds of URLs.
Solution 1: If you specify the URL. Browser will request this to IIS or webserver. MVC doesn't participate in the reading file etc. It gives these requests to IIS to handle. You need to assign permission to the folder.
Solution 2: Read the file in the PresentationModel if you have. read this file in Chunks and return as File type to the browser.
I hope it will give you some direction.
I was able to do this by rewriting paths in an event handler for BeginRequest in global.asax.
BeginRequest += delegate
{
switch (Request.RawUrl.ToLowerInvariant())
{
case "/favicon.ico":
Context.RewritePath("~/Content/favicon.ico");
return;
case "/robots.txt":
Context.RewritePath("~/Content/robots.txt");
return;
}
};
routes.MapRoute("Robots","robots.txt");

Why does MvcHttpHandler is mapped from *.mvc?

By default the web.config file for MVC project have the following element:
<handlers>
<remove name="MvcHttpHandler"/>
<add name="MvcHttpHandler" preCondition="integratedMode"
verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler"/>
</handlers>
My problem is that my site returns 404.14, after knocking out all the usual suspects I changed the path (form the snippet above) attribute in the web.config to be "*" and voilĂ ! MVC handler kicks in.
So my question is how does *.mvc even suppose to work? I mean my urls are http://mysite.com/home/index (or even only http://mysite.com/) there is no *.mvc in them.
Am I missing something?
By changing the path you are telling the routing engine to add the .mvc extension to the Url. You probably do not have the .mvc extension mapped in IIS and receive an error.
See here on information about IIS and MVC especially if you are using IIS 6.0:
http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx

How do I block requests for all *.php, *.cgi, etc. pages from inside an ASP.NET MVC 1.0 app hosted in IIS7?

I'd like to block requests to any .php or .cgi regardless of the pathing information.
For example, when the following url is used:
http://mysite/Admin/Scripts/Setup.php
It matches an existing route:
routeCollection.MapRoute("Admin", "admin/{controller}/{action}/{uid}/{*pathInfo}", new { controller = "Admin", action = "Index", uid = "" });
However there is no controller for scripts so MVC throws the following:
The IControllerFactory '' did
not return a controller for a
controller named 'scripts'.
What I'd really prefer is that the request is simply met with a hard fail before MVC ever got to the controller.
I know that I can do this by hooking the Application_BeginRequest in the Global.asax and throwing a new HttpException(404, "Not Found") but that's not quite the elegant solution I'm looking for.
I was really hoping that this would work:
routeCollection.IgnoreRoute("{resource}.php/{*pathInfo}");
But it doesn't.
NOTE: Sean Lynch's answer works great but I still would really like a System.Web.Routing or System.Web.Mvc based solution. That way I can allow my users to add their own exclusions at runtime.
I know this is an old post but if you're looking for an ignore route for php requests (and some others) including requests within sub folders then I have found the code below works well (adapted from the ignore routes post from Phil Haack)
I also added a specific ignore route for the occasional apple touch icon request (using a wildcard for the different dimensions) and allowed for the different file extensions for the favicon (Google toolbar and some other browsers look for png and gif favicons).
Of course you could add an ignore route for all image file extensions but in my case I still want to route some of the other requests.
routes.IgnoreRoute("{*allphp}", new { allphp = #".*\.php(/.*)?" });
routes.IgnoreRoute("{*allcgi}", new { allcgi = #".*\.cgi(/.*)?" });
routes.IgnoreRoute("{*allaspx}", new { allaspx = #".*\.aspx(/.*)?" });
routes.IgnoreRoute("{*favicons}", new { favicons = #".*favicon\.(ico|gif|png)(/.*)?" });
routes.IgnoreRoute("{*allappleicon}", new { allappleicon = #"apple-touch-icon-.*\.png(/.*)?" });
Despite having these ignore routes, I still think that using request blocking for php files is preferable if you have access to do it.
If you hosting provider supports the IIS7 URL Rewrite module then you could check out this link:
http://learn.iis.net/page.aspx/499/request-blocking---rule-template/
Update here is what you would put into your web.config in the system.webserver section:
<system.webServer>
<rewrite>
<rules>
<rule name="RequestBlockingRule1" patternSyntax="Wildcard">
<match url="*" />
<conditions>
<add input="{URL}" pattern="*.php*" />
</conditions>
<action type="CustomResponse" statusCode="403" />
</rule>
</rules>
</rewrite>
</system.webServer>
I found How to ignore route in asp.net forms url routing which might work for this, it uses the StopRoutingHandler class, and as long as the requests to .php do run through the routing this will probably work.
If the .php requests are not going through the routing handler then this probably wouldn't work.
You could block these extensions before it even hits IIS with Microsoft's UrlScan ISAPI Filter.

Resources