Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 限制到ASP.NET核心中控制器命名空间的路由_C#_Asp.net_Asp.net Core Mvc - Fatal编程技术网

C# 限制到ASP.NET核心中控制器命名空间的路由

C# 限制到ASP.NET核心中控制器命名空间的路由,c#,asp.net,asp.net-core-mvc,C#,Asp.net,Asp.net Core Mvc,我试图将ASP.NET核心路由的控制器限制为某个命名空间 在ASP.NET MVC的早期版本中,有一个重载,在添加路由时提供了string[]namespaces参数。这在ASP.NET MVC 6中缺失。所以在谷歌搜索之后,我试着玩了一些类似的东西 app.UseMvc(routes => { var dataTokens = new RouteValueDictionary { { "Namespaces", new[] {"Projec

我试图将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

更多详情:

我有两个完全独立的WebAPI项目。顺便说一句,有几个路由在这两个方面是相同的(即,
~/api/ping
)。这些项目在生产中是独立的,一个是用户的端点,一个是管理员的端点

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

Microsoft.AspNet.Diagnostics.DeveloperExceptionPageMiddleware:错误:执行请求时发生未经处理的异常
Microsoft.AspNet.Mvc.Infrastructure.AmbiguousActionException:多个操作匹配。以下操作与路线数据匹配,并满足所有约束条件:
ProjectA.SomeNamespace.Controllers.PingController.Ping
ProjectB.SomeNamespace.Controllers.PingController.Ping
位于Microsoft.AspNet.Mvc.Infrastructure.DefaultActionSelector.SelectAsync(RouteContext)
在Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.d_u6.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();
        }
    }
}
第二家庭控制器

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()定义的路由失效

属性路由和基于约定的路由(
路由。MapRoute(…
)独立工作。属性路由比约定路由具有优势

但它似乎没有达到我想要的效果。有没有办法将路由引擎限制在某个名称空间

:

我们建议使用区域来对控制器进行分组,而不是使用名称空间列表。您可以将控制器(无论它们在哪个程序集中)属性化为特定区域,然后为该区域创建路由

您可以在此处看到一个测试网站,其中显示了在MVC6中使用区域的示例:

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

//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
{
    
}
控制器:

//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
{
    
}

谢谢你的精彩回答。这在大多数情况下确实有效,但我认为它在我的特殊情况下是次优的(我应该提供更多细节,我会立即修复):我有两个完全独立的Web API项目。顺便说一句,有几条路线是相同的(即
~/API/ping
)。我使用Microsoft.AspNet.TestHost进行了单元测试。其中一些单元测试需要这两个Web API项目的功能(例如完全设置测试用例)。但是当我引用两个API项目时,
TestHost
会因为相同的路由而变得混乱。非常感谢您的时间,在这里使用路由约束是一个非常好的主意:)我会将您的答案标记为解决方案,您肯定值得,但也会发布另一个答案,因为我不得不稍微改变你的方法,因为
dataTokens
不能与属性路由一起工作。竖起大拇指看区域!很好的解决方案。我使用的是.NET Core 3.1,在调试NamespaceConstraint.IsValidForRequest时发现,routeContext.RouteData.DataTokens不包含启动时endpoints.MapControllerRoute中指定的命名空间。知道为什么没有吗?@RyanPenfold可能是路由系统在没有指定DataToken“多个匹配路由”的情况下选择了不同的路由-你能在这里输入堆栈跟踪的全部错误吗?当然,请查看我更新的问题。