Asp.net mvc 4 如何将磁盘上存在的目录请求路由到ASP.NET MVC?

Asp.net mvc 4 如何将磁盘上存在的目录请求路由到ASP.NET MVC?,asp.net-mvc-4,asp.net-mvc-routing,Asp.net Mvc 4,Asp.net Mvc Routing,我有一个ASP.NET MVC 4应用程序(使用.NET framework 4.5),带有无扩展URL。该站点包含一些静态文件,但所有无扩展请求都应该进入MVC路由 对于以下请求,它都可以正常工作: / /新闻 /fr/新闻 但是,如果我请求/fr,我会得到错误: HTTP Error 403.14 - Forbidden, The Web server is configured to not list the contents of this directory. 我知道这是因为

我有一个ASP.NET MVC 4应用程序(使用.NET framework 4.5),带有无扩展URL。该站点包含一些静态文件,但所有无扩展请求都应该进入MVC路由

对于以下请求,它都可以正常工作:

  • /
  • /新闻
  • /fr/新闻
但是,如果我请求/fr,我会得到错误:

HTTP Error 403.14 - Forbidden, 
The Web server is configured to not list the contents of this directory. 
我知道这是因为磁盘上实际上存在一个/fr目录,但我仍然希望将此请求映射到我的MVC应用程序。它不是删除fr目录的选项,因为它包含一些静态文件

这可能吗?我已经尝试将
runAllManagedModulesForAllRequests=“true”
添加到system.webServer中的modules元素中(我真的不想这样做,但无论如何都没有帮助)

编辑-如果有用,以下是路由:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.IgnoreRoute("cid/{*pathInfo}");
        routes.MapRoute(
           "Page",
           "{*PageId}",
           new { controller = "Page", action = "Page" }, // Parameter defaults
           new { pageId = @"^(.*)?$" } // Parameter constraints
        );
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

阻止访问本地文件夹和文件的最简单方法是设置
RouteCollection.RouteExistingFiles
标志,让ASP.NET处理指向物理文件的URL。因此,请将路线登记更改为:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("cid/{*pathInfo}");

    routes.RouteExistingFiles = true;
    routes.MapRoute(
       "Page",
       "{*PageId}",
       new { controller = "Page", action = "Page" }, // Parameter defaults
       new { pageId = @"^(.*)?$" } // Parameter constraints
    );
}
您的
“默认”
路线不是必需的,因为
“页面”
实际上是一个包罗万象的案例

另一种方法是更改IIS配置,使ASP.NET MVC路由的优先级高于IIS目录列表。在IIS7中,访问您的网站,从IIS部分选择模块,然后从操作选项卡查看有序列表。将UrlRoutingModule移到DirectoryListingModule上方


作为旁注,从你的评论中,我了解到你有一个单一的控制器和一个动作。该操作将服务于除使用
IgnoreRoute
定义的静态资源之外的所有请求。这不是一个推荐的设置,因为您失去了MVC体系结构的所有好处。此外,您会发现页面操作将快速增长,以包含越来越多的案例。这正是路由和控制器设计要解决的问题


如果你认为一个“一网打尽”的方法对你来说是最好的解决方案,那么你就不需要MVC,最好使用请求开销小得多的Web API。

编辑:我最初认为有必要删除DirectoryListingModule,但事实并非如此,在此之前,我的自定义HttpModule重写将生效,因此可以保留它

我用来解决这个问题的解决方法是向正在执行一些请求处理的定制HttpModule添加一些逻辑。在这里,我检测请求是否对应于我的一个本地化(/fr//es/etc)的根,如果是,则将url重写为默认页面/fr/索引,路由正常工作

private void BeginRequest(object sender, EventArgs e)
{
    HttpApplication application = (HttpApplication)sender;
    HttpContext context = application.Context;
    var url = context.Request.Url.AbsolutePath;
    if (IsLocalizationRoot(url))
    {
        context.RewritePath(url + GetDefaultPageName());
    }
}
如果您对如何删除DirectoryListingModule感兴趣(如上所述,这不是必需的,但它还是有用的信息):

当StaticFileHandler引用它时,您需要删除它,然后在web.config中删除并重新添加StaticFileHandler(不带DirectoryListingModule):

<system.webServer>
    <handlers>
      <remove name="StaticFile"/>
      <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule" 
           resourceType="Either" requireAccess="Read" />  
    </handlers>
    <modules>
      <remove name="DirectoryListingModule"/>
    </modules>
</system.webServer>

我添加了路由,尽管我不确定这是否相关,因为MVC路由从来不会对/fr请求生效。我很确定这是由于DirectoryListingModule拾取了它,但我无法从图片中看出这一点(如所述:)请查看此处不确定这有何帮助,如前所述,我无法删除/fr目录。对于应用程序中的/fr请求,您希望发生什么?您是否创建了一个包含Index()操作的FrController?我认为添加runAllManagedModulesForAllRequests=true是正确的。我怀疑默认路由处理程序正在将/fr请求传递给目录处理程序,这解释了上面的IIS错误。创建一个自定义路由处理程序来拦截/fr请求并将其路由到MVC控制器如何?我希望避免通过MVC路由推送物理文件请求,因为我无法想象这不会对我的静态产生任何性能影响。感谢关于MVC体系结构的额外建议,不过别担心,这是一个“合适的”MVC架构!应用程序连接到CMS,因此当请求传入时,我们首先将请求url映射到CMS中的页面对象,该对象定义了一组要触发的子操作(使用默认路由和使用一组控制器、操作和视图的普通MVC内容)@路由无疑会对性能产生影响,但它可能比你想象的要小。ASP.NET尝试将尽可能多的请求处理推送到IIS,而IIS处理程序非常擅长缓存。因此,如果您的安装是在IIS 7+上托管的ASP.NET 4.0+,那么我就不会太担心性能。在这里查看更多细节:虽然我的解决方案与你的有点不同,但你付出了努力,让我重新思考,你得到了赏金!虽然这是可行的,但感觉像是一种解决办法,所以我想知道是否有一个纯配置解决方案,它不涉及HTTP模块,也不涉及通过MVC路由静态请求……它也不是解决现有目录未被路由问题的通用解决方案,尽管它适用于我的用例
appcmd set module DirectoryListingModule /lockItem:false