查看将从路线执行哪个控制器和动作?

Mat*_*zen 5 c# routing asp.net-core

在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); 
Run Code Online (Sandbox Code Playgroud)

Com*_*Guy 5

它看起来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;
}
Run Code Online (Sandbox Code Playgroud)

它首先尝试通过模板匹配所有路由。它称为IActionSelector,它会完成其余的工作。你可以这样使用它:

var action = GetMatchingAction("/api/users/28", "GET"); // will return null if no matching route found
Run Code Online (Sandbox Code Playgroud)