พบการกระทำหลายอย่างที่ตรงกับคำขอใน Web Api


243

ฉันได้รับข้อผิดพลาดนี้อย่างต่อเนื่องเมื่อพยายามใช้วิธี 2 "รับ"

พบการกระทำหลายอย่างที่ตรงกับคำขอ: webapi

ฉันได้ดูรอบ ๆ คำถามที่คล้ายกันเกี่ยวกับเรื่องนี้ในกอง แต่ฉันไม่ได้รับมัน

ฉันมี 2 ชื่อต่างกันและใช้แอตทริบิวต์ "HttpGet"

[HttpGet]
public HttpResponseMessage Summary(MyVm vm)
{
    return null;
}

[HttpGet]
public HttpResponseMessage FullDetails()
{
    return null;
}

คำตอบ:


485

แผนที่เส้นทางของคุณน่าจะเป็นแบบนี้:

routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });

แต่เพื่อให้มีการดำเนินการหลายอย่างด้วยวิธี http เดียวกันคุณจำเป็นต้องให้ข้อมูลเพิ่มเติมกับ webapi ผ่านเส้นทางดังนี้:

routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });

ขอให้สังเกตว่าตอนนี้เส้นทางเทมเพลตมีการดำเนินการอยู่ ข้อมูลเพิ่มเติมมากมายที่นี่: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

ปรับปรุง:

เอาล่ะตอนนี้ฉันคิดว่าฉันเข้าใจสิ่งที่คุณหลังจากที่นี่เป็นอีกหนึ่งใช้เวลานี้:

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

ตัวอย่างเช่นสองวิธีของคุณอาจกลายเป็น:

public HttpResponseMessage Get()
{
    return null;
}

public HttpResponseMessage Get(MyVm vm)
{
    return null;
}

คุณใช้ข้อมูลชนิดใดในวัตถุ MyVm หากคุณสามารถส่งผ่านตัวแปรผ่าน URI ได้ฉันขอแนะนำให้ไปที่เส้นทางนั้น มิฉะนั้นคุณจะต้องส่งวัตถุในเนื้อความของคำขอและนั่นไม่ใช่ HTTP ของคุณเมื่อทำการ GET (ใช้งานได้แค่ใช้ [FromBody] infront ของ MyVm)

หวังว่าสิ่งนี้แสดงให้เห็นว่าคุณสามารถมีวิธีการหลายวิธีในตัวควบคุมเดียวโดยไม่ต้องใช้ชื่อการกระทำหรือแม้กระทั่งแอตทริบิวต์ [HttpGet]


มีข้อดีของการทำทางเดียวหรือไม่? ถ้าฉันทำรองฉันจะต้องใส่การกระทำของ http ในแต่ละวิธี? นั่นคือการดึงกลับที่ยิ่งใหญ่?
chobo2

3
ไม่ว่าคนหนึ่งจะได้เปรียบกว่าอีกคนหนึ่งนั้นขึ้นอยู่กับโครงการของคุณหรือไม่ หากคุณกำลังสร้าง api RESTful คุณจะต้องใช้การประชุม HTTP (GET, POST, PUT, DELETE ... ) ในกรณีนี้บล็อกแรกของรหัสเส้นทางเป็นวิธีที่จะไป แต่คุณจะต้องการตัวควบคุมที่แตกต่างกันสำหรับทุกเอนทิตีที่คุณเปิดเผยผ่าน api จากชื่อวิธีการของคุณฉันเดาว่านี่ไม่ใช่กรณีนี้ดังนั้นให้ใช้การกำหนดเส้นทางแบบอธิบายเพิ่มเติม เมื่อเส้นทางของคุณมีการดำเนินการคุณจะต้องใส่แอตทริบิวต์ http ในแต่ละวิธีอย่างชัดเจน
Jed

1
@ chobo2 ทำไมไม่เพียงใช้วิธีการที่มีชื่อตามภายในคอนโทรลเลอร์? GetSummary (MyVm wm) และ GetDetails ()
Jed

1
ขอบคุณสำหรับคำตอบของคุณเพียงแค่ช่วยฉันหาสาเหตุที่ความละเอียดของเส้นทางไม่ทำงานแม้ว่าการกระทำของฉันทั้งสองจะมีชื่อแตกต่างกัน ฉันสับสนจริง ๆ ว่าทำไมไม่เพียง แต่พฤติกรรมเริ่มต้น (เช่นทำไมเทมเพลตเส้นทางเริ่มต้นใน webapiconfig.cs inlcude "{action}")!
Tejas Sharma

1
@bruno ถ้าใช้พื้นที่ที่คุณยังสามารถเพิ่ม 'ผู้ดูแลระบบ' APIs ที่เฉพาะเจาะจงเช่นนี้ใน AdminAreaRegistration stackoverflow.com/a/9849011/16940
Simon_Weaver

67

อัปเดตตั้งแต่ Web API 2

ด้วยการกำหนดค่า API นี้ในไฟล์ WebApiConfig.cs ของคุณ:

public static void Register(HttpConfiguration config)
{
    //// Web API routes
    config.MapHttpAttributeRoutes(); //Don't miss this

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

คุณสามารถกำหนดเส้นทางผู้ควบคุมของเราดังนี้:

[Route("api/ControllerName/Summary")]
[HttpGet]
public HttpResponseMessage Summary(MyVm vm)
{
    rturn null;
}

[Route("api/ControllerName/FullDetails")]
[HttpGet]
public HttpResponseMessage FullDetails()
{
    return null;
}

โดยที่ ControllerName เป็นชื่อของคอนโทรลเลอร์ของคุณ (โดยไม่มี "controller") วิธีนี้จะช่วยให้คุณได้รับการดำเนินการตามเส้นทางที่มีรายละเอียดด้านบน

สำหรับการอ่านเพิ่มเติม: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2


ฉันชอบวิธีนี้มาก เส้นทางเริ่มต้นของฉันยังคงเหมือนเดิมและฉันมีเส้นทาง "ข้อยกเว้น" สำหรับข้อยกเว้น
Leandro De Mello Fagundes

นอกจากนี้คุณยังสามารถแมปพารามิเตอร์ลงใน URL EX: [เส้นทาง ("api / ControllerName / สรุป / {vm}")]
nulltron

15

ใน Web API (ค่าเริ่มต้น) วิธีการได้รับการแต่งตั้งขึ้นอยู่กับการรวมกันของ HTTP วิธีการและเส้นทางค่า

MyVmดูเหมือนว่าเป็นวัตถุที่ซับซ้อนอ่านโดยตัวจัดรูปแบบจากเนื้อความดังนั้นคุณจึงมีสองวิธีที่เหมือนกันในแง่ของข้อมูลเส้นทาง (เนื่องจากไม่มีพารามิเตอร์ใด ๆ จากเส้นทาง) - ซึ่งทำให้เป็นไปไม่ได้สำหรับโปรแกรมเลือกจ่ายงาน ( IHttpActionSelector) เพื่อให้ตรงกับวิธีที่เหมาะสม .

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


14

หลังจากค้นหาเว็บจำนวนมากและพยายามหารูปแบบที่เหมาะสมที่สุดสำหรับแผนที่เส้นทางหากพบสิ่งต่อไปนี้

config.Routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id =RouteParameter.Optional }, new { id = @"\d+" });
config.Routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");

การแม็พเหล่านี้ใช้กับการแม็พชื่อแอ็คชันและหลักการ http พื้นฐาน (GET, POST, PUT, DELETE)


9
สำหรับฉันแล้วสิ่งนี้ทำงานได้ แต่หลังจากเปลี่ยนลำดับของเส้นทางในการกำหนดค่าเส้นทางเพื่อให้เส้นทางที่มีการดำเนินการปรากฏขึ้นก่อน
Fredrik Stolpe

ว่าคำสั่งที่สำคัญที่นี่
AT

5

อาจเป็นไปได้ว่าวิธีการเว็บของคุณกำลังแก้ไขเป็น URL เดียวกัน ดูลิงค์ต่อไปนี้: -

http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

ดังนั้นคุณอาจต้องเพิ่ม methodname ของคุณในตารางเส้นทางของคุณ


5

ตัวเลือกจะเป็น:

  1. ย้ายหนึ่งในวิธีการไปยังตัวควบคุมที่แตกต่างกันเพื่อให้พวกเขาไม่ได้ปะทะกัน

  2. ใช้เพียงวิธีเดียวที่ใช้พารามิเตอร์และถ้าเป็นโมฆะเรียกวิธีอื่นจากรหัสของคุณ


อาจเป็นวิธีการแก้ปัญหา แต่ไม่ใช่วิธีที่ดีที่สุด +1 จากด้านข้างของฉัน :)
satish kumar V

4

วิธีนี้ใช้ได้ผลสำหรับฉัน

โปรดวาง Route2 เป็นอันดับแรกใน WebApiConfig เพิ่ม HttpGet และ HttpPost ก่อนแต่ละวิธีรวมถึงชื่อคอนโทรลเลอร์และชื่อเมธอดใน URL

WebApiConfig =>

config.Routes.MapHttpRoute(
           name: "MapByAction",
           routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional });
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });

ตัวควบคุม =>

public class ValuesController : ApiController
{

    [HttpPost]
    public string GetCustomer([FromBody] RequestModel req)
    {
        return "Customer";
    }

    [HttpPost]
    public string GetCustomerList([FromBody] RequestModel req)
    {
        return "Customer List";
    }
}

URL =>

http://localhost:7050/api/Values/GetCustomer

http://localhost:7050/api/Values/GetCustomerList

4

นี่คือคำตอบสำหรับทุกคนที่รู้ว่าทุกอย่างถูกต้องและได้ตรวจสอบ 50 ครั้ง .....

RouteConfig.csให้แน่ใจว่าคุณไม่ได้มองไปที่ซ้ำแล้วซ้ำอีก

ชื่อไฟล์ที่คุณต้องการแก้ไข WebApiConfig.cs

นอกจากนี้ควรมีลักษณะเช่นนี้:

using System.Web.Http;

namespace My.Epic.Website
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
          config.MapHttpAttributeRoutes();

          // api/Country/WithStates
          config.Routes.MapHttpRoute(
            name: "ControllerAndActionOnly",
            routeTemplate: "api/{controller}/{action}",
            defaults: new { },
            constraints: new { action = @"^[a-zA-Z]+([\s][a-zA-Z]+)*$" });

          config.Routes.MapHttpRoute(
            name: "DefaultActionApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
          );
    }
    }
}

ฉันสามารถช่วยตัวเองได้ประมาณ 3 ชั่วโมง


1
ขอบคุณคุณช่วยฉันประมาณ 3 ชั่วโมง
geedubb

3

ฉันพบว่าเมื่อฉันมีสองวิธีการรับหนึ่งตัวแปรและหนึ่งที่มีประเภทที่ซับซ้อนเป็นพารามิเตอร์ที่ฉันได้รับข้อผิดพลาดเดียวกัน ฉันแก้ไขได้โดยเพิ่มพารามิเตอร์ดัมมี่ของ type int ชื่อ Id เป็นพารามิเตอร์แรกของฉันแล้วตามด้วยพารามิเตอร์ประเภทที่ซับซ้อนของฉัน ฉันเพิ่มพารามิเตอร์ชนิดที่ซับซ้อนลงในเทมเพลตเส้นทาง ต่อไปนี้ใช้งานได้สำหรับฉัน

ก่อนได้รับ:

public IEnumerable<SearchItem> Get()
{
...
}

รับที่สอง:

public IEnumerable<SearchItem> Get(int id, [FromUri] List<string> layers)
{
...
}

WebApiConfig:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}/{layers}",
    defaults: new { id = RouteParameter.Optional, layers RouteParameter.Optional }
);

3

เป็นไปได้เนื่องจากการใช้ตัวควบคุม MVC แทนตัวควบคุม Web API ตรวจสอบเนมสเปซในตัวควบคุม Web API ที่ควรมีดังต่อไปนี้

using System.Net;
using System.Net.Http;
using System.Web.Http;

หากเนมสเปซมีดังต่อไปนี้แสดงว่ามีข้อผิดพลาดดังกล่าวข้างต้นในการเรียกเมธอดควบคุมเว็บ api

using System.Web;
using System.Web.Mvc;

2

โปรดตรวจสอบว่าคุณมีสองวิธีซึ่งมีชื่อและพารามิเตอร์เหมือนกัน

ถ้าเป็นเช่นนั้นโปรดลบวิธีการใด ๆ แล้วลอง


2

ฉันสะดุดกับปัญหานี้ในขณะที่พยายามเพิ่มตัวควบคุม WebAPI ของฉันด้วยการกระทำพิเศษ

สมมติว่าคุณจะมี

public IEnumerable<string> Get()
{
    return this.Repository.GetAll();
}

[HttpGet]
public void ReSeed()
{
    // Your custom action here
}

ขณะนี้มีสองวิธีที่ตอบสนองคำขอ / api / คอนโทรลเลอร์ที่ก่อให้เกิดปัญหาที่อธิบายโดย TS

ฉันไม่ต้องการเพิ่มพารามิเตอร์ "จำลอง" ในการกระทำเพิ่มเติมของฉันดังนั้นฉันจึงดูการกระทำเริ่มต้นและมาพร้อมกับ:

[ActionName("builtin")]
public IEnumerable<string> Get()
{
    return this.Repository.GetAll();
}

สำหรับวิธีแรกร่วมกับการผูกเส้นทาง "คู่":

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { action = "builtin", id = RouteParameter.Optional },
    constraints: new { id = @"\d+" });

config.Routes.MapHttpRoute(
    name: "CustomActionApi",
    routeTemplate: "api/{controller}/{action}");

โปรดทราบว่าแม้ว่าจะไม่มีพารามิเตอร์ "การกระทำ" ในแม่แบบเส้นทางแรกเห็นได้ชัดว่าคุณยังสามารถกำหนดค่าการกระทำเริ่มต้นช่วยให้เราสามารถแยกเส้นทางของการเรียก "ปกติ" WebAPI การโทรและการเรียกร้องให้ดำเนินการพิเศษ


2

ในกรณีของฉันทุกอย่างถูกต้อง

1) การกำหนดค่าเว็บถูกกำหนดค่าอย่างเหมาะสม 2) คำนำหน้าเส้นทางและแอตทริบิวต์เส้นทางมีความเหมาะสม

ฉันยังคงได้รับข้อผิดพลาด ในแอตทริบิวต์ Case ของฉัน "Route" (โดยการกด F12) ได้ชี้ไปที่ System.Web.MVc แต่ไม่ใช่ System.Web.Http ซึ่งทำให้เกิดปัญหา


คำตอบนี้ช่วยฉันได้มาก!
tvb108108

1

คุณสามารถเพิ่ม[Route("api/[controller]/[action]")]ไปยังคลาสตัวควบคุมของคุณ

[Route("api/[controller]/[action]")]
[ApiController]
public class MySuperController : ControllerBase
{
 ...
}

0

ฉันรู้ว่ามันเป็นคำถามเก่า แต่บางครั้งเมื่อคุณใช้ทรัพยากรบริการเช่นจาก AngularJS เพื่อเชื่อมต่อกับ WebAPI ตรวจสอบให้แน่ใจว่าคุณใช้เส้นทางที่ถูกต้องและข้อผิดพลาดอื่น ๆ ที่ชาญฉลาดเกิดขึ้น


0

ตรวจสอบให้แน่ใจว่าคุณไม่ได้ตกแต่งวิธีการควบคุมของคุณสำหรับการกระทำเริ่มต้น GET | PUT | POST | DELETE ด้วยแอตทริบิวต์ [HttpPost / Put / Get / Delete] ฉันได้เพิ่มคุณสมบัตินี้ไปยังการกระทำของตัวควบคุม Vanilla Post และทำให้ 404

หวังว่าสิ่งนี้จะช่วยให้ใครบางคนสามารถทำลายและนำความก้าวหน้ามาสู่การหยุดชะงัก


0

ตัวอย่างเช่น => TestController

        [HttpGet]
        public string TestMethod(int arg0)
        {
            return "";
        }

        [HttpGet]
        public string TestMethod2(string arg0)
        {
            return "";
        }

        [HttpGet]
        public string TestMethod3(int arg0,string arg1)
        {
            return "";
        }

หากคุณสามารถเปลี่ยนไฟล์ WebApiConfig.cs เท่านั้น

 config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/",
                defaults: null
            );

แค่นั้นแหละ :)

และผลลัพธ์: ป้อนคำอธิบายรูปภาพที่นี่


0

คุณเคยลองไหม:

[HttpGet("Summary")]
public HttpResponseMessage Summary(MyVm vm)
{
    return null;
}

[HttpGet("FullDetails")]
public HttpResponseMessage FullDetails()
{
    return null;
}

1
สิ่งนี้จะไม่คอมไพล์ในโครงการที่ไม่ใช่. NET Core เนื่องจากHttpGetแอตทริบิวต์ไม่มีตัวสร้างที่ยอมรับอาร์กิวเมนต์สตริง
Hoppeduppeanut
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.