C# 使用RouteAttribute或隐式路由时的WebApi路径差异

C# 使用RouteAttribute或隐式路由时的WebApi路径差异,c#,.net,asp.net-web-api,routing,C#,.net,Asp.net Web Api,Routing,我一直在使用WebApi,我试图理解使用Route属性与让WebApi基于函数名自动创建路由的区别。我有许多这种形式的控制器: public class MyController : RestControllerBase { public async Task<HttpResponseMessage> GetData() { return _data; } [Route(ApiVersion.Version + "/MyControl

我一直在使用WebApi,我试图理解使用Route属性与让WebApi基于函数名自动创建路由的区别。我有许多这种形式的控制器:

public class MyController : RestControllerBase
{
    public async Task<HttpResponseMessage> GetData()
    {
        return _data;
    }

    [Route(ApiVersion.Version + "/MyController/{param}/specific/route")]
    public async Task<HttpResponseMessage> GetMoreData()
    {
        return _moreData;
    }
}
当我构建和测试API时,两个端点都可以正确访问

我还使用了一个基于名称空间(用于版本控制)的HttpControllerSelector来覆盖HttpControllerSelector

我的问题是,除了被特定http路由调用的传统功能外,这两个路由的行为也不同。例如,在我的重写控制器选择器中,我必须编写此逻辑,以便控制器和路由正确映射:

private string GetControllerName(IHttpRouteData routeData)
{
    if (routeData.GetSubRoutes() != null)
    {
        // With route attribute
        var subroute = routeData.GetSubRoutes().FirstOrDefault();
        var dataTokenValue = subroute.Route.DataTokens["actions"];
        if (dataTokenValue == null) return null;
        var controllername = ((HttpActionDescriptor[])dataTokenValue).First().ControllerDescriptor.ControllerName.Replace("Controller", string.Empty);
        return controllername;
    }
    else
    {
        // Try Strategy for without route attribute.
        return (String)routeData.Values["controller"];
    }
}

private string GetVersion(IHttpRouteData routeData)
{
    var routeTemplate = "";
    if (routeData.GetSubRoutes() != null)
    {
        var subRouteData = routeData.GetSubRoutes().FirstOrDefault();
        if (subRouteData == null) return null;
        routeTemplate = subRouteData.Route.RouteTemplate;
    }
    else
    {
        routeTemplate = routeData.Route.RouteTemplate;
    }

    var index = routeTemplate.IndexOf("/");
    if (index == -1)
    {
        return Unversioned;
    }
    var version = routeTemplate.Substring(0, index).ToUpperInvariant();
    return version;
}
似乎具有显式属性的路由将有一个route.GetSubroutes()可用,而隐式路由则不可用。 这导致我编写了两种不同的方法来从传入请求中提取版本和控制器名称,然后才能正确路由它们。我可以接受这一点,但WebApi内部的某些东西正在创建路由之间的这种区别,这确实让我感到困扰

不幸的是,我随后开始使用来记录我的api,并遇到了类似的问题。swagger页面为具有Route属性的路由正确生成,但完全忽略隐式路由。我怀疑导致此问题的问题与导致选择逻辑中的分支的问题相同

我已经在网上找到了尽可能多的ApiExplorer、WebAPI和其他文档,但是我还没有找到使隐式/显式路由方法同质化的解决方案。这甚至可能是它们实现中的一个bug


我应该从这里走到哪里?

所以这里的答案是Web Api 2存在缺陷或不一致 要进行验证,可以运行此代码段。在我提到的例子中,ApiExplorer不会为没有明确标记路由属性的路径返回结果

        IApiExplorer apiExplorer = configuration.Services.GetApiExplorer();
        foreach (ApiDescription api in apiExplorer.ApiDescriptions)
        {
            Console.WriteLine("Uri path: {0}", api.RelativePath);
            Console.WriteLine("HTTP method: {0}", api.HttpMethod);
            foreach (ApiParameterDescription parameter in api.ParameterDescriptions)
            {
                Console.WriteLine("Parameter: {0} - {1}", parameter.Name, parameter.Source);
            }
            Console.WriteLine();
        }
        IApiExplorer apiExplorer = configuration.Services.GetApiExplorer();
        foreach (ApiDescription api in apiExplorer.ApiDescriptions)
        {
            Console.WriteLine("Uri path: {0}", api.RelativePath);
            Console.WriteLine("HTTP method: {0}", api.HttpMethod);
            foreach (ApiParameterDescription parameter in api.ParameterDescriptions)
            {
                Console.WriteLine("Parameter: {0} - {1}", parameter.Name, parameter.Source);
            }
            Console.WriteLine();
        }