ChatGPT解决这个技术问题 Extra ChatGPT

Web API 路由 - api/{controller}/{action}/{id} “dysfunctions” api/{controller}/{id}

我在 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} 的路线的教程甚至提到这个问题。


C
Chris Li

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

所以,你应该:

将您的特定规则放在一般规则之前(如默认规则),这意味着首先使用 RouteTable.Routes.MapHttpRoute 来映射“WithActionApi”,然后是“DefaultApi”。删除默认值:“WithActionApi”规则的新 { id = System.Web.Http.RouteParameter.Optional } 参数,因为一旦 id 是可选的,像“/api/{part1}/{part2}”这样的 url 将永远不会进入“默认API”。将命名操作添加到您的“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。阅读有关属性路由的信息。
M
MSTdev

您可以在属性路由的帮助下解决您的问题

控制器

[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); }
P
Pang

尝试这个。

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 }

        );
    }
}

P
Paritosh Tiwari

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


D
Derek Wade

要区分路线,请尝试添加 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 }
         );