我已经创建了一个GitHub repo来更好地理解这里的问题。我在绑定到同一路径的两个不同控制器上有两个动作。
foo map bar
由于存在两个匹配的路由,因此默认的ActionSelector失败并显示:
'[...] AmbiguousActionException:匹配多个动作。 [...]” 这是可以理解的。
所以我想我可以实现我的own ActionSelector。在那里,我将实现逻辑,通过相同的逻辑解决多个路由的问题,具体取决于'标识符'路由值(代码中的line 27)
如果'标识符'值是a - >然后是FirstController
如果'标识符'值为b - >然后是SecondController
依旧......
http://localhost/sameControllerRoute/{identifier}/values
[Route("sameControllerRoute")]
public class FirstController : Controller
{
public FirstController()
{
// different EF Core DataContext than SecondController and possibly other dependencies than SecondController
}
[HttpGet("{identifier}/values")]
public IActionResult Values(string identifier, DateTime from, DateTime to) // other parameters than SecondController/Values
{
return this.Ok("Was in FirstController");
}
}
[Route("sameControllerRoute")]
public class SecondController : Controller
{
public SecondController()
{
// different EF Core DataContext than FirstController and possibly other dependencies than FirstController
}
[HttpGet("{identifier}/values")]
public IActionResult Values(string identifier, int number, string somethingElse) // other parameters than FirstController/Values
{
return this.Ok("Was in SecondController");
}
}
但是我没有找到一个很好的解决方案来获取ActionSelector中的路由值。这也是可以理解的,因为ModelBinding还没有开始,因为MVC仍在试图找出路线。
一个肮脏的解决方案可能是以某种方式抓住 protected override IReadOnlyList<ActionDescriptor> SelectBestActions(IReadOnlyList<ActionDescriptor> actions)
{
if (actions.HasLessThan(2)) return base.SelectBestActions(actions); // works like base implementation
foreach (var action in actions)
{
if (action.Parameters.Any(p => p.Name == "identifier"))
{
/*** get value of identifier from route (launchSettings this would result in 'someIdentifier') ***/
// call logic that decides whether value of identifier matches the controller
// if yes
return new List<ActionDescriptor>(new[] { action }).AsReadOnly();
// else
// keep going
}
}
return base.SelectBestActions(actions); // fail in all other cases with AmbiguousActionException
}
和正则表达式。
但是我仍然希望你能提供一个更好的想法来检索路由值,即使ModelBinding还没有在请求管道中发生。
答案 0 :(得分:0)
不确定您是否需要根据场景使用ActionSelector。因此,对于提供的代码,您的控制器使用不同类型的资源(因此他们期望不同的查询参数)。因此,最好使用不同的路由模板。像这样的东西:
/sameControllerRoute/resourceA/{identifier}/values
/sameControllerRoute/resourceB/{identifier}/values
在REST的范围内,当我们讨论/sameControllerRoute/{identifier}/values
路由模板时,我们希望不同的identifier
表示相同的资源类型,但资源名称不同。因此,作为API使用者,我们希望支持所有以下请求
/sameControllerRoute/a/values?from=20160101&to=20170202
/sameControllerRoute/b/values?from=20160101&to=20170202
/sameControllerRoute/a/values?number=1&somethingElse=someData
/sameControllerRoute/b/values?number=1&somethingElse=someData
在您的情况下情况并非如此
答案 1 :(得分:0)
我最终由ASP.NET团队实现了提议的solution。这是为了实现IActionConstrain,如下所示:
//displayText