MVC ignoring .jpg file extension on certain route

2019-08-03 16:42发布

问题:

I'm trying to serve image files from a specific url system, like so:

mysite/Images/Category/File_Name.extension

I've set up a route like so:

routes.MapRoute( "ImagesRoute", // Route name 
                 "Images/{category}/{file}.jpg", // URL with parameters 
                 new { controller = "Posts", 
                       action = "ViewImage", 
                       category = "", file = "" } // Parameter defaults 
                );

Which is supposed to map to my controller action:

public ActionResult ViewImage(string category, string file)
    {
        var dir = Server.MapPath("/Images");
        var imgtitle = file.Replace("_", " ").Replace(".jpg", "");
        var repos = new BlogImagesRepository();
        var guid = repos.FetchImageByCategoryAndTitle(category, imgtitle);
        var path = Path.Combine(dir, category, guid.ImageGuid.ToString());
        return File(path, "image/jpeg");
    }

If I remove the .jpg extension from the route and request a file title without the .jpg extension on the url (ie: Images/MyCategory/My_Image) it displays just fine. However, adding the .jpg extension results in a 404 error--

The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

I assume it's looking for the file, instead of the controller action.

Adding the .jpg to the routes did not resolve this; I'm unsure what to do, and my google luck hasn't been very high with similar questions I saw on here.

How can I do this for .jpg, and similar image types? Do I have to set up an ignore for that particular path somehow? If so, how do I go about doing that? The application is just being ran through VS 2012 currently.

回答1:

You're right in that requests for .jpg aren't being sent through to your Controller and handled by the static file handler of IIS. You don't really want an ignore, but you want to pass it through to the ASP.NET runtime. Most of the internet searches you'll find will tell you to add RunAllManagedModulesForAllRequests or something to that respect; however, this has a performance impact so the easiest way to do this is probably to add another TransferRequestHandler in your web config, like the MyJpgHandler example below:

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />

    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />    

      <add name="MyJpgHandler" path="Images/*/*.jpg" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

      <add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" />
    </handlers>
  </system.webServer>

This should result in behaviour you're expecting (assuming you don't also have any .jpg files that are meant to be served as static content from the same url path)