控制器在单独的装配和路由中

本文关键字:路由 单独 控制器 | 更新日期: 2023-09-27 18:37:27

在同一解决方案中,有一个 ASP.NET MVC4应用程序Slick.App和类库Awesome.Mvc.Lib。Awesome.Mvc.Lib包含一个控制器类。

public class ShinnyController : Controller
{
    [HttpGet]
    public string Index()
    {
        return "Hello, from Awesome.Mvc.Lib";
    }
}

如果我只是将 Slick.App 的引用添加到 Awesome.Mvc.Lib,运行应用程序并将浏览器指向/shinny,我实际上会看到响应"你好,来自 Awesome.Mvc.Lib"。

这是我完全没有想到的。我一直认为 MVC ASP.NET 尊重控制器放置的命名空间。因此,来自另一个命名空间的控制器不会公开,至少在我没有要求之前。

我尝试更改默认路由注册,以使用命名空间参数。

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces: new [] { "Slick.App.Controllers" }
    );

尽管如此,ShinnyController 路由仍然与"/shinny"匹配。

我担心这是正确的默认行为。我的问题是,如何明确说明公开了哪些控制器并防止默认路由匹配单独类库中的控制器?

控制器在单独的装配和路由中

路由上的命名空间列表仅将某些命名空间的优先级置于其他命名空间之上,这些命名空间未列出:

new [] {"Namespace1", "Namespace2"}

不会像人们期望的那样为 Namespace1 提供更高的优先级,而只是赋予两个命名空间比其他命名空间更高的优先级。

这意味着首先在列表中的命名空间中搜索控制器,然后,如果未找到匹配项,则使用该名称的其余可用控制器。

您可以通过执行以下操作来禁止使用非优先级控制器:

var myRoute  = routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces: new [] { "Slick.App.Controllers" }
    );
myRoute.DataTokens["UseNamespaceFallback"] = false;

你可以像这样从 DefaultControllerFactory 继承:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        var type = base.GetControllerType(requestContext, controllerName);
        if (type != null && IsIngored(type))
        {
            return null;
        }
        return type;
    }
    public static bool IsIngored(Type type)
    {
        return type.Assembly.GetCustomAttributes(typeof(IgnoreAssemblyAttribute), false).Any() 
            || type.GetCustomAttributes(typeof(IgnoreControllerAttribute), false).Any();
    }
}

然后对 Global.asax 进行一些更改

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
        ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
    }

你来了!任何标记为 IgnoreControllerAttribute 的类型都将不可见。您甚至可以隐藏整个程序集。

如果您需要一些基于配置的行为,那么进行所有必要的更改并不是一件大事;)