【问题标题】:Web API Routing - api/{controller}/{action}/{id} "dysfunctions" api/{controller}/{id}Web API 路由 - api/{controller}/{action}/{id} “dysfunctions” api/{controller}/{id}
【发布时间】:2012-11-28 01:39:17
【问题描述】:

我在 Global.asax 中有默认路由:

 RouteTable.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

我希望能够针对特定功能,所以我创建了另一条路线:

RouteTable.Routes.MapHttpRoute(
         name: "WithActionApi",
         routeTemplate: "api/{controller}/{action}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

所以,在我的控制器中,我有:

    public string Get(int id)
    {
        return "object of id id";
    }        

    [HttpGet]
    public IEnumerable<string> ByCategoryId(int id)
    {
        return new string[] { "byCategory1", "byCategory2" };
    }

致电.../api/records/bycategoryid/5 会给我我想要的。 但是,调用.../api/records/1 会给我错误

找到多个与请求匹配的操作:...

我明白为什么会这样 - 路由只是定义了哪些 URL 是有效的,但是在函数匹配方面,Get(int id)ByCategoryId(int id) 都匹配 api/{controller}/{id},这是 混淆框架。

我需要做些什么才能让默认 API 路由再次工作,并保留带有 {action} 的路由?我想创建一个名为RecordByCategoryIdController 的不同控制器来匹配默认的API 路由,我会为此请求.../api/recordbycategoryid/5。但是,我发现这是一个“肮脏”(因此不令人满意)的解决方案。我一直在寻找这方面的答案,但没有关于使用{action} 的路线的教程甚至提到这个问题。

【问题讨论】:

    标签: asp.net routing controller asp.net-web-api action


    【解决方案1】:

    路由引擎使用与您添加规则相同的顺序。一旦获得第一个匹配的规则,它将停止检查其他规则并以此搜索控制器和操作。

    所以,你应该:

    1. 将您的特定规则放在一般规则之前(如默认),这意味着使用RouteTable.Routes.MapHttpRoute 先映射“WithActionApi”,然后映射“DefaultApi”。

    2. 删除“WithActionApi”规则的 defaults: new { id = System.Web.Http.RouteParameter.Optional } 参数,因为一旦 id 是可选的,像“/api/{part1}/{part2}”这样的 url 将永远不会进入“DefaultApi”。

    3. 向您的“DefaultApi”添加一个命名操作,以告诉路由引擎要输入哪个操作。否则,一旦您的控制器中有多个操作,引擎将不知道要使用哪个操作并抛出“找到与请求匹配的多个操作:...”。然后要使其与您的 Get 方法匹配,请使用 ActionNameAttribute

    所以你的路线应该是这样的:

    // Map this rule first
    RouteTable.Routes.MapRoute(
         "WithActionApi",
         "api/{controller}/{action}/{id}"
     );
    
    RouteTable.Routes.MapRoute(
        "DefaultApi",
        "api/{controller}/{id}",
        new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
    );
    

    还有你的控制器:

    [ActionName("DefaultAction")] //Map Action and you can name your method with any text
    public string Get(int id)
    {
        return "object of id id";
    }        
    
    [HttpGet]
    public IEnumerable<string> ByCategoryId(int id)
    {
        return new string[] { "byCategory1", "byCategory2" };
    }
    

    【讨论】:

    • 我尝试了上面的建议,一切都按预期工作。非常感谢你的“秘密”。
    • 在您的回答中的第 2 点,如果 id 是可选的,那么如果没有为 WithActionApi 路由找到匹配的操作,则像 /api/{part1}/{part2} 这样的 URL 仍可能进入 DefaultApi 路由。如果我错了,请纠正我。
    • 如果我只想拥有 api/{controller}/{action} 会发生什么。没有身份证。如果其他人面临同样的问题。忘记 WebApiConfig。阅读属性路由。
    【解决方案2】:

    属性路由可以解决你的问题

    控制器

    [Route("api/category/{categoryId}")]
    public IEnumerable<Order> GetCategoryId(int categoryId) { ... }
    

    jQuery 中的 URI

    api/category/1
    

    路由配置

    using System.Web.Http;
    
    namespace WebApplication
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                // Other Web API configuration not shown.
            }
        }
    }
    

    并且您的默认路由作为默认基于约定的路由

    工作

    控制器

    public string Get(int id)
        {
            return "object of id id";
        }   
    

    Jquery 中的 URI

    /api/records/1 
    

    路由配置

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Attribute routing.
            config.MapHttpAttributeRoutes();
    
            // Convention-based routing.
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
    

    查看文章了解更多信息Attribute routing and onvention-based routing here & this

    【讨论】:

    • 上帝的答案。但是我们不能为所有人添加 api/{controller}/{action}/{id} 以及 api/{controller}/{id} 吗?
    • 属性路由绝对解决了这个问题。重要一点:在 Web API 2 之前,Web API 项目模板生成的代码如下: protected void Application_Start() { WebApiConfig.Register(GlobalConfiguration.Configuration); }如果启用了属性路由,这段代码会抛出异常。如果您升级现有 Web API 项目以使用属性路由,请确保将此配置代码更新为以下内容:protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); }
    【解决方案3】:

    试试这个。

    public class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
    
            var json = config.Formatters.JsonFormatter;
            json.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
            config.Formatters.Remove(config.Formatters.XmlFormatter);
    
            // Web API routes
            config.MapHttpAttributeRoutes();
    
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional , Action =RouteParameter.Optional }
    
            );
        }
    }
    

    【讨论】:

      【解决方案4】:

      可能的原因也可能是你没有从 ApiController 继承 Controller。 发生在我身上花了一段时间才明白。

      【讨论】:

        【解决方案5】:

        要区分路由,请尝试添加 id 必须为数字的约束:

        RouteTable.Routes.MapHttpRoute(
                 name: "DefaultApi",
                 routeTemplate: "api/{controller}/{id}",
                 constraints: new { id = @"\d+" }, // Only matches if "id" is one or more digits.
                 defaults: new { id = System.Web.Http.RouteParameter.Optional }
                 );  
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-13
          • 2013-10-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多