限制路由到 ASP.NET Core 中的控制器命名空间
Restrict route to controller namespace in 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
。其中一些单元测试需要这两个 Web API 项目的功能(即需要 "admin" 端点才能为 "user" 完全设置测试用例)。但是当我引用两个 API 项目时,TestHost 会因为相同的路由而感到困惑,并抱怨 "multiple matching routes":
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.<RouteAsync>d__6.MoveNext()
更新:
我通过使用 ActionConstraint 找到了解决方案。您必须添加关于重复操作的自定义操作约束属性。
具有重复索引方法的示例。
第一个家庭控制器
namespace WebApplication.Controllers
{
public class HomeController : Controller
{
[NamespaceConstraint]
public IActionResult Index()
{
return View();
}
}
}
第二个家庭控制器
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;
}
}
}
第一个回答:
Does attribute routing funk up the routes defined by app.UseMvc()?
属性路由和基于约定的路由 (routes.MapRoute(...
) 独立工作。并且属性路由比约定路由有优势。
but it doesn't seem to do what I want. Is there a way to restrict the routing engine to a certain namespace?
Instead of using a list of namespaces to group your controllers we recommend using Areas. You can attribute your controllers (regardless of which assembly they are in) with a specific Area and then create a route for that Area.
You can see a test website that shows an example of using Areas in MVC 6 here: 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" });
}
基于属性的路由使用区域的示例
//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
{
}
我正在尝试将我的 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
。其中一些单元测试需要这两个 Web API 项目的功能(即需要 "admin" 端点才能为 "user" 完全设置测试用例)。但是当我引用两个 API 项目时,TestHost 会因为相同的路由而感到困惑,并抱怨 "multiple matching routes":
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.<RouteAsync>d__6.MoveNext()
更新:
我通过使用 ActionConstraint 找到了解决方案。您必须添加关于重复操作的自定义操作约束属性。
具有重复索引方法的示例。
第一个家庭控制器
namespace WebApplication.Controllers
{
public class HomeController : Controller
{
[NamespaceConstraint]
public IActionResult Index()
{
return View();
}
}
}
第二个家庭控制器
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;
}
}
}
第一个回答:
Does attribute routing funk up the routes defined by app.UseMvc()?
属性路由和基于约定的路由 (routes.MapRoute(...
) 独立工作。并且属性路由比约定路由有优势。
but it doesn't seem to do what I want. Is there a way to restrict the routing engine to a certain namespace?
Instead of using a list of namespaces to group your controllers we recommend using Areas. You can attribute your controllers (regardless of which assembly they are in) with a specific Area and then create a route for that Area.
You can see a test website that shows an example of using Areas in MVC 6 here: 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" });
}
基于属性的路由使用区域的示例
//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
{
}