如何在MVC模块下禁用IIS DirectoryListingModule或重新确定其优先级



我使用MVC文件夹结构,其中URL路由恰好与目录名匹配,例如:

<proj>MyCoolThingThingController.cs

需要通过以下网址访问:

http://blahblah/My/Cool/Thing

我有MVC路由,但不幸的是,当依赖默认的{action}&{id},IIS Express将请求路由到DirectoryListingModule,因为它直接与文件夹名称匹配。目录列表当然被禁用了,所以我得到了:

The Web server is configured to not list the contents of this directory.
Module     DirectoryListingModule
Notification       ExecuteRequestHandler
Handler    StaticFile

为了解决这个问题,我已经尝试过:

1. runAllManagedModulesForAllRequests = true
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" >   
//Makes no difference
2. Removing module
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" >
<remove name="DirectoryListingModule"/>   
// Won't let me as module is locked in IIS
</modules>
</system.webServer>
3. Removing lock & module
// applicationhost.config
<add name="DirectoryListingModule" lockItem="false" />
// web.config
<remove name="DirectoryListingModule"/>
// Causes startup error"Handler "StaticFile" has a bad module "DirectoryListingModule" in its module list"

4. Removing lock & removing/readding module (to change order) - makes no difference
// web.config
<remove name="DirectoryListingModule"/>
<add name="DirectoryListingModule"/>

把我的头发扯掉。如何让IIS将其路由到我的MVC应用程序,而不是DirectoryListingModue??最好是web.config中的解决方案,这样我们就不需要在生产中重新配置IIS。

(一个解决方法是保留我的文件夹结构,但将其全部存储在/Areas/…下,只是为了打破文件夹路径和url之间的匹配。这是一个可怕的破解和最后的手段。)

编辑以添加路线映射

我正在创建相对于每个控制器的名称空间的自定义路由(名称空间总是与文件夹匹配)。请注意,目前所有内容都放在"模块"名称空间/文件夹下,只是为了避免上述问题。

private static void RegisterAllControllers(RouteCollection routes)
{
const string controllerSuffix = "Controller";
const string namespacePrefix = "My.Cool.Websire.UI.Modules.";
var controllerTypes = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsSubclassOf(typeof(Controller))).ToList();
foreach (var controllerType in controllerTypes)
{
// Turn My.Cool.Website.UI.Modules.X.Y.Z.Abc.AbcController into a route for url /X/Y/Z/Abc/{action}/{id}
var fullNamespace = controllerType.Namespace ?? "";
var relativeNamespace = fullNamespace.Substring(namespacePrefix.Length, fullNamespace.Length - namespacePrefix.Length);
var controllerName =
controllerType.Name.EndsWith(controllerSuffix)
? controllerType.Name.Substring(0, controllerType.Name.Length - controllerSuffix.Length)
: controllerType.Name;
var url = relativeNamespace.Replace(".", "/") + "/{action}/{id}";
var routeName = "Dedicated " + controllerName + " route";
routes.MapRoute(routeName, url, new { controller = controllerName, action = "Index", id = UrlParameter.Optional });
}
}

现阶段我的解决方案是将WebUI项目的MVC内容放在/Modules/文件夹下:

My.Cool.Site.WebUI/Modules/Something/Blah/BlahController
My.Cool.Site.WebUI/Modules/Something/Blah/Views/...
My.Cool.Site.WebUI/Modules/Something/Blah/PartialViews/...

然后使用发布的路线代码,我可以通过url:访问

http://.../Something/Blah/[action]

因为这些文件位于/Modules/文件夹下,这打破了URL和文件夹路径之间的匹配,从而解决了我的问题。

这不是一个很好的解决方案,但确实有效。

我认为,如果你想把控制器放在文件夹中,这样它们就不在"控制器"之下,你应该使用MVC提供的"区域"功能。它就是为这个目的而设计的。

我注意到,如果我有一个自定义的http模块,从web.config指向,比如

<modules>
<remove name="WebDAVModule" />
<add name="CustomHttpModule" type="MyCompany.Types.CustomHttpModule" preCondition="managedHandler" />
</modules>

然后,我可以在DirectoryListingModule劫持进程之前运行代码,但当我检测到它即将进入物理文件夹时,我还不知道该怎么办。

using System.IO;
using System.Web;
using System.Linq;
using System.Linq.Expressions;
namespace MyCompany.Types
{
public class CustomHttpModule : IHttpModule
{
public void OnAcquireRequestState(object sender, EventArgs ea)
{
List<string> physicalFolders = Directory.EnumerateDirectories(AppContext.BaseDirectory).Select(f => f.Substring(1 + f.LastIndexOf('\'))).ToList();
string projectBase = /* get from web.config */.TrimStart('/');
string possiblePhysicalFolder = application.Request.Url.AbsolutePath.TrimStart('/').Replace(projectBase, "").TrimStart('/');
if (physicalFolders.Exists(f => possiblePhysicalFolder.StartsWith(f)))
/* what to do??? */;
}

相关内容

  • 没有找到相关文章

最新更新