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

查看:190
本文介绍了限制到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).这些项目在生产中是独立的,一个是用户的端点,一个是管理员的端点.

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"端点才能为用户"完全设置测试用例).但是当我引用两个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();
        }
    }
}

第二个HomeController

Second 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()定义的路由起作用?

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?

开发者的答复:

我们建议使用Areas,而不是使用名称空间列表对控制器进行分组.您可以为控制器分配一个特定区域(无论它们在哪个程序集中),然后为该区域创建一条路线.

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.

将区域用于基于约定的路由的示例

控制器:

//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天全站免登陆