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

2020-01-22 11:39发布

问题:

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?

回答1:

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.



回答2:

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



回答3:

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" />


回答4:

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



回答5:

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>


回答6:

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/


回答7:

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 + "/" }) |


回答8:

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.



回答9:

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.



回答10:

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



回答11:

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



回答12:

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.



回答13:

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".



回答14:

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);


回答15:

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> 


回答16:

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.



回答17:

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");
        }
    }
}