限制路由到 ASP.NET Core 中的控制器命名空间 [英] Restrict route to controller namespace in ASP.NET Core

查看:24
本文介绍了限制路由到 ASP.NET Core 中的控制器命名空间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将我的 ASP.NET Core 路由的控制器限制到某个命名空间.

I'm trying to restrict the controllers of my ASP.NET Core routes to a certain namespace.

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

In previous versions of ASP.NET MVC there was an overload that provided a string[] namespaces parameter when adding routes. This is missing in ASP.NET MVC 6. So after some googling, I tried playing around with something like

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
    );
});

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

but it doesn't seem to do what I want. Is there a way to restrict the routing engine to a certain namespace?

更新

我刚刚意识到这可能与我在每个单独的控制器上使用属性路由这一事实有关?属性路由是否对 app.UseMvc() 定义的路由进行了限定?

I just realized it may have to do something with the fact that I'm using attribute routing on each individual controller? Does attribute routing funk up the routes defined by app.UseMvc()?

更新 2

更多细节:

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

I've two completely independent Web API projects. Incidentally, a few of the routes are identical in both (ie. ~/api/ping). These projects are independent in Production, one is an endpoint for users, one is an endpoint for administrators.

我也有单元测试,使用 Microsoft.AspNet.TestHost.其中一些单元测试需要这两个 Web API 项目的功能(即需要admin"端点来为user"完全设置测试用例).但是当我引用这两个 API 项目时,TestHost 会因为相同的路由而感到困惑,并抱怨多个匹配路由":

I also have unit tests, using Microsoft.AspNet.TestHost. A few of these unit tests require functionality of both of these Web API projects (ie. need "admin" endpoint to fully setup a test case for "user"). But when I reference both API projects, the TestHost gets confused because of the identical routes and it complains about "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 找到了解决方案.您必须添加有关重复操作的自定义操作约束属性.

I've found solution through using ActionConstraint. You have to add custom Action Constraint attribute about duplicate actions.

具有重复索引方法的示例.

Example with duplicate Index methods.

第一个 HomeController

First HomeController

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;
        }
    }
}

第一个答案:

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

Does attribute routing funk up the routes defined by app.UseMvc()?

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

Attribute routing and Convention-based routing (routes.MapRoute(...) work independently. And attribute routes have advantage over convention routes.

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

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.

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

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 Core 中的控制器命名空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆