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

时间:2017-09-04 13:39:40

标签: c# asp.net-core routing

在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); 

2 个答案:

答案 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}]}]