在ASP .NET Core中,我如何给出一个路由(例如/api/users/28
),看看将使用哪个控制器,以及将使用哪个动作?例如,在这种情况下,它将是UsersController
及其Get(int id)
操作。
如果有办法访问某种可以告诉我这个的路由器,我很乐意,所以我不必自己复制内部路由系统。我还没有能够使用ASP .NET Core路由的官方文档找到它。
编辑1 我的问题不重复。我没有找到确定路线是否存在的选项 - 我想知道确切的动作和控制器将处理它。
编辑2 以下是我当前代码的样子,以及我尝试过的内容:
var httpContext = new DefaultHttpContext();
httpContext.Request.Path = "/api/users/28";
httpContext.Request.Method = "GET";
var context = new RouteContext(httpContext);
//throws an exception: AmbiguousActionException: Multiple actions matched.
var bestCandidate = _actionSelector.SelectBestCandidate(context,
_actionDescriptorCollectionProvider.ActionDescriptors.Items);
答案 0 :(得分:2)
看起来IActionSelector
仅匹配HTTP方法等,并完全忽略路由模板。
感谢Sets回答和https://blog.markvincze.com/matching-route-templates-manually-in-asp-net-core/,我提出了以下解决方案:
public ManualActionSelector(IActionSelector actionSelector, IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
{
_actionSelector = actionSelector;
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
}
public ActionDescriptor GetMatchingAction(string path, string httpMethod)
{
var actionDescriptors = _actionDescriptorCollectionProvider.ActionDescriptors.Items;
// match by route template
var matchingDescriptors = new List<ActionDescriptor>();
foreach (var actionDescriptor in actionDescriptors)
{
var matchesRouteTemplate = MatchesTemplate(actionDescriptor.AttributeRouteInfo.Template, path);
if (matchesRouteTemplate)
{
matchingDescriptors.Add(actionDescriptor);
}
}
// match action by using the IActionSelector
var httpContext = new DefaultHttpContext();
httpContext.Request.Path = path;
httpContext.Request.Method = httpMethod;
var routeContext = new RouteContext(httpContext);
return _actionSelector.SelectBestCandidate(routeContext, matchingDescriptors.AsReadOnly());
}
public bool MatchesTemplate(string routeTemplate, string requestPath)
{
var template = TemplateParser.Parse(routeTemplate);
var matcher = new TemplateMatcher(template, GetDefaults(template));
var values = new RouteValueDictionary();
return matcher.TryMatch(requestPath, values);
}
// This method extracts the default argument values from the template. From https://blog.markvincze.com/matching-route-templates-manually-in-asp-net-core/
private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate)
{
var result = new RouteValueDictionary();
foreach (var parameter in parsedTemplate.Parameters)
{
if (parameter.DefaultValue != null)
{
result.Add(parameter.Name, parameter.DefaultValue);
}
}
return result;
}
它首先尝试通过模板匹配所有路由。它调用IActionSelector
,其余部分完成。您可以像这样使用它:
var action = GetMatchingAction("/api/users/28", "GET"); // will return null if no matching route found
答案 1 :(得分:1)
如果您有HttpContext
个实例,则可以
//using Microsoft.AspNetCore.Mvc.Infrastructure;
//using Microsoft.AspNetCore.Routing;
//HttpContext httpContext;
//IActionDescriptorCollectionProvider provider
//IActionSelector selector
var routeContext = new RouteContext(httpContext);
var x = selector.SelectBestCandidate(routeContext, provider.ActionDescriptors.Items);
var route = new
{
Action = x.RouteValues["Action"],
Controller = x.RouteValues["Controller"],
Name = x.AttributeRouteInfo.Name,
Template = x.AttributeRouteInfo.Template,
Constrains = x.ActionConstraints,
};
您可以使用IActionDescriptorCollectionProvider
服务(default MVC implementation)找到所有操作并分析Template
字符串:
//IActionDescriptorCollectionProvider provider
var routes = provider.ActionDescriptors.Items.Select(x => new {
Action = x.RouteValues["Action"],
Controller = x.RouteValues["Controller"],
Name = x.AttributeRouteInfo.Name,
Template = x.AttributeRouteInfo.Template,
Constrains = x.ActionConstraints
}).ToList();
要让HTTP方法查看Constrains
- 这是IActionConstraintMetadata
项的列表。其中,将有HttpMethodActionConstrains
项包含用于操作的HTTP方法。
结果示例:
[{"action":"GetValues","controller":"Values","name":null,"template":"api/Values","constrains":[{"httpMethods":["GET"],"order":100}]},
{"action":"GetValuesById","controller":"Values","name":null,"template":"api/Values/{id}","constrains":[{"httpMethods":["GET"],"order":100}]},
{"action":"PostValue","controller":"Values","name":null,"template":"api/Values","constrains":[{"httpMethods":["POST"],"order":100}]},
{"action":"PutValue","controller":"Values","name":null,"template":"api/Values/{id}","constrains":[{"httpMethods":["PUT"],"order":100}]},
{"action":"DeleteValue","controller":"Values","name":null,"template":"api/Values/{id}","constrains":[{"httpMethods":["DELETE"],"order":100}]}]