การกำหนดเส้นทาง Web API - api / {controller} / {action} / {id}“ dysfunctions” api / {controller} / {id}


94

ฉันมีเส้นทางเริ่มต้นใน 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}พูดถึงปัญหานี้เลย

คำตอบ:


105

เครื่องมือกำหนดเส้นทางใช้ลำดับเดียวกันกับที่คุณเพิ่มกฎเข้าไป เมื่อได้กฎที่ตรงกันข้อแรกแล้วกฎจะหยุดตรวจสอบกฎอื่น ๆ และใช้สิ่งนี้เพื่อค้นหาตัวควบคุมและการดำเนินการ

ดังนั้นคุณควร:

  1. วางกฎเฉพาะของคุณไว้ข้างหน้ากฎทั่วไปของคุณ (เช่นค่าเริ่มต้น) ซึ่งหมายถึงใช้RouteTable.Routes.MapHttpRouteเพื่อจับคู่ "WithActionApi" ก่อนจากนั้นจึง "DefaultApi"

  2. ลบdefaults: new { id = System.Web.Http.RouteParameter.Optional }พารามิเตอร์ของกฎ "WithActionApi" ของคุณเนื่องจากเมื่อ id เป็นทางเลือก URL เช่น "/ api / {part1} / {part2}" จะไม่เข้าสู่ "DefaultApi"

  3. เพิ่มการดำเนินการที่มีชื่อใน "DefaultApi" ของคุณเพื่อบอกเครื่องมือกำหนดเส้นทางว่าจะป้อนการดำเนินการใด มิฉะนั้นเมื่อคุณมีการดำเนินการมากกว่าหนึ่งอย่างในคอนโทรลเลอร์ของคุณเอ็นจิ้นจะไม่ทราบว่าควรใช้การดำเนินการใดและแสดงข้อความ "พบการดำเนินการหลายรายการที่ตรงกับคำขอ: ... " จากนั้นจะให้มันตรงกับวิธีการรับของคุณใช้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" };
}

1
ฉันลองทำตามคำแนะนำข้างต้นและทุกอย่างเป็นไปตามที่คาดไว้ ขอบคุณมากสำหรับ "ความลับ" นั้น
Mickael Caruso

ในจุดที่ 2 ในคำตอบของคุณหากidเป็นทางเลือก URL like /api/{part1}/{part2}อาจยังเข้าสู่DefaultApiเส้นทางหากไม่พบการดำเนินการที่ตรงกันสำหรับWithActionApiเส้นทาง กรุณาแก้ไขฉันถ้าฉันผิด
orad

จะเกิดอะไรขึ้นถ้าฉันต้องการมี api / {controller} / {action} เท่านั้น ไม่มีรหัส หากมีผู้อื่นประสบปัญหาเดียวกัน ลืมเกี่ยวกับ WebApiConfig อ่านเกี่ยวกับ Attribute Routing
อา

40

คุณสามารถแก้ปัญหาของคุณได้ด้วยความช่วยเหลือของ การกำหนดเส้นทางแอตทริบิวต์

ตัวควบคุม

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

URI ใน jquery

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";
    }   

URI ใน Jquery

/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 }
        );
    }
}

อ่านบทความสำหรับข้อมูลเพิ่มเติมการกำหนดเส้นทางแอตทริบิวต์และการกำหนดเส้นทางตามการประดิษฐ์ที่นี่และสิ่งนี้


คำตอบของพระเจ้า แต่เพิ่มทั้งหมดไม่ได้ api / {controller} / {action} / {id} พร้อมกับ api / {controller} / {id}?
karim

การกำหนดเส้นทางแอตทริบิวต์ช่วยแก้ปัญหาได้อย่างแน่นอน จุดสำคัญประการหนึ่ง: ก่อนหน้า Web API 2 เทมเพลตโครงการ Web API จะสร้างโค้ดเช่นนี้: protected void Application_Start () {WebApiConfig.Register (GlobalConfiguration.Configuration); } หากเปิดใช้งานการกำหนดเส้นทางแอตทริบิวต์รหัสนี้จะทำให้เกิดข้อยกเว้น หากคุณอัปเกรดโครงการ Web API ที่มีอยู่เพื่อใช้การกำหนดเส้นทางแอตทริบิวต์ตรวจสอบให้แน่ใจว่าได้อัปเดตโค้ดคอนฟิกูเรชันนี้เป็นดังต่อไปนี้: protected void Application_Start () {GlobalConfiguration.Configure (WebApiConfig.Register); }
Deeb

0

ลองทำตามนี้

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 }

        );
    }
}

0

สาเหตุที่เป็นไปได้ก็คือคุณไม่ได้สืบทอด Controller จาก ApiController เกิดขึ้นกับฉันใช้เวลาสักครู่เพื่อให้เข้าใจตรงกัน


0

หากต้องการแยกความแตกต่างของเส้นทางให้ลองเพิ่มข้อ จำกัด ที่ 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 }
         );  
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.