Background
In HomeController.cs
I have:
[HttpGet]
public GetPerson(string name)
{
return View(new PersonModel { ... });
}
In Global.asax.cs
I have:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Word", "person/{name}",
new { controller = "Home", action = "GetPerson" });
routes.MapRoute(
"Default", "{controller}/{action}",
new { controller = "Home", action = "Index" });
}
In SomePage.cshtml
I have, effectively, this:
@{ var name = "Winston S. Churchill"; }
<a href="@Url.Action("GetPerson", "Home", new { name })">@name</a>
Problem
If I click the link for Winston S. Churchill, I am routed to the URL http://localhost/person/Winston%20S.%20Churchill
, which yields the standard 404 page:
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
This only happens if the name
variable contains a .
(period). All my code works perfectly fine when the name is, for example, Winston Churchill
.
How can I make ASP.NET MVC 3 percent-encode the .
(period) in the URL?
Or, how can I make the routing work without .
(period) being percent-encoded?
Unacceptable Workaround (if presented without justification)
If I change the route to the following, everything works.
routes.MapRoute(
"Word", "person",
new { controller = "Home", action = "GetPerson" });
However, the URL becomes http://localhost/person?name=Winston%20S.%20Churchill
, which isn't what I want. I want the name
in the path part of the URL, not the query.
1 Answer 1
Routes which contain a period and unknown extension are interpreted by IIS as static files and not sent through the .NET pipeline. For example, the URL you cite is interpreted as a static file with a %20Churchill
extension.
You can force ASP.NET to handle all requests by adding this to web.config
:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
You'll also need this, to handle name
values that end with a period (as opposed to just containing one):
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
All /person/{name}
URLs will then be picked up by your ASP.NET code.
If you would rather not use this setting, the easiest workaround would be to use a custom encoding:
name.Replace(".","--")
-
1Are there any safety issues with this that could be unexpected?Timothy Shields– Timothy Shields2013年08月10日 01:50:07 +00:00Commented Aug 10, 2013 at 1:50
-
2Also, while this works for
Winston S. Churchill
(I just tried it), it fails forAlbert Gore Jr.
(note period at end).Timothy Shields– Timothy Shields2013年08月10日 01:53:18 +00:00Commented Aug 10, 2013 at 1:53 -
2No safety issues, but it means that ASP.NET will try to process all requests so files that actually are static (images, CSS, etc.) will take a tiny bit longer to load. In practice, you are unlikely to notice a difference. To fix the issue with the terminating period, try adding
<httpRuntime relaxedUrlToFileSystemMapping="true" />
to<system.web>
.James– James2013年08月10日 01:57:32 +00:00Commented Aug 10, 2013 at 1:57 -
1The issue with runAllManagedModulesForAllRequests is not really a security one, but with performance since all requests will be handled by managed modules even request for static files.Andy T– Andy T2013年08月10日 01:57:41 +00:00Commented Aug 10, 2013 at 1:57
-
1Excellent. My site has very little static content (shortcut icon is it so far). The two changes you outlined worked great. I'm going to edit your answer to highlight the
relaxedUrlToFileSystemMapping
setting.Timothy Shields– Timothy Shields2013年08月10日 02:06:34 +00:00Commented Aug 10, 2013 at 2:06