在ASP.NET Core中限制到控制器命名空间的路由

我试图将我的ASP.NET核心路由的控制器限制到某个命名空间。

在以前版本的ASP.NET MVC中,有一个重载在添加路由时提供了string[] namespaces参数。 ASP.NET MVC 6中缺少这个。所以在谷歌搜索之后,我尝试了类似的东西

 app.UseMvc(routes => { var dataTokens = new RouteValueDictionary { { "Namespaces", new[] {"ProjectA.SomeNamespace.Controllers"} } }; routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}", defaults: null, constraints: null, dataTokens: dataTokens ); }); 

但它似乎没有做我想要的。 有没有办法将路由引擎限制在某个命名空间?

更新

我刚刚意识到它可能必须对我在每个控制器上使用属性路由这一事实做些什么? 属性路由是否会影响app.UseMvc()定义的路由?

更新2

更多细节:

我有两个完全独立的Web API项目。 顺便提一下,一些路由在两者中都是相同的(即~/api/ping )。 这些项目在Production中是独立的,一个是用户的端点,一个是管理员的端点。

我还使用Microsoft.AspNet.TestHost进行unit testing。 其中一些unit testing需要这两个Web API项目的function(即需要“admin”端点来完全为“用户”设置测试用例)。 但是,当我引用两个API项目时,TestHost因为相同的路由而感到困惑,并抱怨“多个匹配的路由”:

 Microsoft.AspNet.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request Microsoft.AspNet.Mvc.Infrastructure.AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied: ProjectA.SomeNamespace.Controllers.PingController.Ping ProjectB.SomeNamespace.Controllers.PingController.Ping at Microsoft.AspNet.Mvc.Infrastructure.DefaultActionSelector.SelectAsync(RouteContext context) at Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.d__6.MoveNext() 

更新:

我通过使用ActionConstraint找到了解决方案。 您必须添加有关重复操作的自定义Action Constraint属性。

重复索引方法的示例。

第一个HomeController

 namespace WebApplication.Controllers { public class HomeController : Controller { [NamespaceConstraint] public IActionResult Index() { return View(); } } } 

第二个HomeController

 namespace WebApplication { public class HomeController : Controller { [NamespaceConstraint] public IActionResult Index() { return View(); } } } 

配置路由

 app.UseMvc(cR => cR.MapRoute("default", "{controller}/{action}", null, null, new { Namespace = "WebApplication.Controllers.HomeController" })); 

行动约束

 namespace WebApplication { public class NamespaceConstraint : ActionMethodSelectorAttribute { public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action) { var dataTokenNamespace = (string)routeContext.RouteData.DataTokens.FirstOrDefault(dt => dt.Key == "Namespace").Value; var actionNamespace = ((ControllerActionDescriptor)action).MethodInfo.DeclaringType.FullName; return dataTokenNamespace == actionNamespace; } } } 

第一个答案:

属性路由是否会影响app.UseMvc()定义的路由?

属性路由和基于约定的路由( routes.MapRoute(... )独立工作。属性路由优于常规路由。

但它似乎没有做我想要的。 有没有办法将路由引擎限制在某个命名空间?

开发人员回答 :

我们建议使用区域,而不是使用命名空间列表来对控制器进行分组。 您可以将控制器(无论它们位于哪个组件中)归属于特定区域,然后为该区域创建路径。

您可以在此处看到一个测试网站,其中显示了在MVC 6中使用区域的示例: https : //github.com/aspnet/Mvc/tree/dev/test/WebSites/RoutingWebSite 。

使用具有基于约定的路由的Area的示例

控制器:

 //Reached through /admin/users //have to be located into: project_root/Areas/Admin/ [Area("Admin")] public class UsersController : Controller { } 

配置基于约定的路由:

  app.UseMvc(routes => { routes.MapRoute( "areaRoute", "{area:exists}/{controller}/{action}", new { controller = "Home", action = "Index" }); } 

使用具有基于属性的路由的Area的示例

 //Reached through /admin/users //have to be located into: project_root/Areas/Admin/ [Area("Admin")] [Route("[area]/[controller]/[action]", Name = "[area]_[controller]_[action]")] public class UsersController : Controller { }