Nhiều hành động đã được tìm thấy phù hợp với yêu cầu trong Web Api


243

Tôi liên tục gặp lỗi này khi tôi cố gắng có 2 phương thức "Nhận"

Nhiều hành động đã được tìm thấy phù hợp với yêu cầu: webapi

Tôi đã xem xét các câu hỏi tương tự khác về vấn đề này trên stack nhưng tôi không hiểu.

Tôi có 2 tên khác nhau và sử dụng thuộc tính "HttpGet"

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

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

Câu trả lời:


485

Bản đồ lộ trình của bạn có lẽ là một cái gì đó như thế này:

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

Nhưng để có nhiều hành động với cùng một phương thức http, bạn cần cung cấp cho webapi nhiều thông tin hơn qua tuyến đường như vậy:

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

Lưu ý rằng routeTemplate hiện bao gồm một hành động. Nhiều thông tin hơn ở đây: http://www.asp.net/web-api/overview/web-api-routing-and-ilities/routing-in-aspnet-web-api

Cập nhật:

Được rồi, bây giờ tôi nghĩ rằng tôi hiểu những gì bạn đang ở đây là một điều khác:

Có lẽ bạn không cần tham số url hành động và nên mô tả nội dung mà bạn đang theo sau theo cách khác. Vì bạn đang nói rằng các phương thức đang trả về dữ liệu từ cùng một thực thể, sau đó chỉ cần để các tham số thực hiện mô tả cho bạn.

Ví dụ, hai phương thức của bạn có thể được chuyển thành:

public HttpResponseMessage Get()
{
    return null;
}

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

Loại dữ liệu nào bạn đang truyền trong đối tượng MyVm? Nếu bạn có thể chuyển các biến qua URI, tôi khuyên bạn nên đi theo tuyến đó. Mặt khác, bạn sẽ cần gửi đối tượng trong phần yêu cầu và đó không phải là HTTP của bạn khi thực hiện GET (mặc dù nó hoạt động, chỉ cần sử dụng [FromBody] trước MyVm).

Hy vọng rằng điều này minh họa rằng bạn có thể có nhiều phương thức GET trong một bộ điều khiển duy nhất mà không cần sử dụng tên hành động hoặc thậm chí là thuộc tính [HttpGet].


Có bất kỳ lợi thế của việc làm theo cách này hay cách khác? Nếu tôi làm thứ cấp, tôi chỉ phải đặt hành động http trên mỗi phương thức? Đó có phải là sự thu hút lớn?
chobo2

3
Việc một người nắm giữ lợi thế so với người kia thực sự phụ thuộc vào dự án của bạn. Nếu bạn đang xây dựng một api RESTful, thì bạn sẽ muốn sử dụng các quy ước HTTP (GET, POST, PUT, DELETE ...). Trong trường hợp này, khối mã định tuyến đầu tiên là cách để đi nhưng bạn sẽ muốn một bộ điều khiển khác nhau cho mọi thực thể mà bạn tiếp xúc thông qua api. Dựa trên tên phương thức của bạn, tôi đoán đây không phải là trường hợp nên sử dụng định tuyến mô tả nhiều hơn. Khi tuyến đường của bạn bao gồm hành động bạn sẽ muốn đặt rõ ràng thuộc tính http trên mỗi phương thức.
Jed

1
@ chobo2 Tại sao không sử dụng các phương thức được đặt tên phù hợp trong bộ điều khiển? GetSummary (MyVm wm) và GetDetails ()
Jed

1
Cảm ơn câu trả lời của bạn, chỉ giúp tôi tìm ra lý do tại sao độ phân giải tuyến đường không hoạt động mặc dù cả hai hành động của tôi có tên khác nhau. Tôi thực sự bối rối về lý do tại sao không chỉ là hành vi mặc định (tức là tại sao mẫu tuyến đường mặc định trong webapiconfig.cs lại inlcude "{action}")!
Tejas Sharma

1
@bruno nếu sử dụng khu vực bạn cũng có thể thêm 'admin' API cụ thể như thế này trong AdminAreaRegistration stackoverflow.com/a/9849011/16940
Simon_Weaver

67

Cập nhật kể từ API Web 2.

Với cấu hình API này trong tệp WebApiConfig.cs của bạn:

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

Bạn có thể định tuyến bộ điều khiển của chúng tôi như thế này:

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

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

Trong đó ControllerName là tên của bộ điều khiển của bạn (không có "bộ điều khiển"). Điều này sẽ cho phép bạn có được từng hành động với lộ trình chi tiết ở trên.

Để đọc thêm: http://www.asp.net/web-api/overview/web-api-routing-and-ilities/attribution-routing-in-web-api-2


Tôi thực sự thích giải pháp này. Tuyến đường mặc định của tôi vẫn giống nhau và tôi có tuyến đường "ngoại lệ" cho các ngoại lệ
Leandro De Mello Fagundes

bạn cũng có thể ánh xạ các tham số vào url EX: [Tuyến đường ("api / ControllerName / Summary / {vm}")]
nulltron

15

Trong API Web (theo mặc định), các phương thức được chọn dựa trên sự kết hợp của các giá trị tuyến và phương thức HTTP .

MyVmtrông giống như một đối tượng phức tạp, được đọc bởi trình định dạng từ cơ thể để bạn có hai phương thức giống nhau về dữ liệu tuyến đường (vì cả hai đều không có bất kỳ tham số nào từ tuyến đường) - điều này khiến cho bộ điều phối ( IHttpActionSelector) không thể khớp với phương thức thích hợp .

Bạn cần phân biệt chúng theo chuỗi truy vấn hoặc tham số tuyến để giải quyết sự mơ hồ.


14

Sau rất nhiều lần tìm kiếm trên web và cố gắng tìm ra hình thức phù hợp nhất cho bản đồ định tuyến nếu đã tìm thấy sau đây

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

Các ánh xạ này áp dụng cho cả ánh xạ tên hành động và quy ước http cơ bản (GET, POST, PUT, DELETE)


9
Đối với tôi điều này đã hoạt động, nhưng chỉ sau khi thay đổi thứ tự các tuyến đường trong cấu hình tuyến đường để cái có hành động xuất hiện đầu tiên
Fredrik Stolpe

chính xác thứ tự là quan trọng ở đây
AT


5

Không sử dụng các hành động, các tùy chọn sẽ là:

  1. di chuyển một trong các phương thức sang một bộ điều khiển khác để chúng không bị xung đột.

  2. chỉ sử dụng một phương thức lấy tham số và nếu nó không gọi phương thức khác từ mã của bạn.


Nó có thể là giải pháp, nhưng không phải là tối ưu, dù sao cũng là +1 từ phía tôi :)
satish kumar V

4

Giải pháp này đã làm việc cho tôi.

Vui lòng đặt Route2 trước trong WebApiConfig. Đồng thời Thêm httpGet và HttpPost trước mỗi phương thức và bao gồm tên của trình điều khiển và tên phương thức trong 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 });

Bộ điều khiển =>

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

Đây là câu trả lời cho tất cả những người biết mọi thứ đều đúng và đã kiểm tra 50 lần .....

Hãy chắc chắn rằng bạn không liên tục nhìn vào RouteConfig.cs.

Tập tin bạn muốn chỉnh sửa được đặt tên WebApiConfig.cs

Ngoài ra, nó có thể trông giống hệt như thế này:

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

Tôi có thể đã tự cứu mình khoảng 3 giờ.


1
Cảm ơn, bạn đã cứu tôi khoảng 3 giờ
geedubb

3

Tôi thấy rằng khi tôi có hai phương thức Get, một tham số và một phương thức có kiểu phức là tham số mà tôi gặp lỗi tương tự. Tôi đã giải quyết điều này bằng cách thêm một tham số giả của kiểu int, được đặt tên là Id, làm tham số đầu tiên của tôi, theo sau là tham số loại phức tạp của tôi. Sau đó tôi đã thêm tham số loại phức tạp vào mẫu tuyến đường. Sau đây làm việc cho tôi.

Nhận đầu tiên:

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

Nhận thứ hai:

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

Có thể do sử dụng bộ điều khiển MVC thay vì bộ điều khiển API Web. Kiểm tra không gian tên trong bộ điều khiển API Web, nó sẽ như sau

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

Nếu không gian tên như sau thì đó là lỗi trên trong cách gọi phương thức điều khiển api web

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

2

Vui lòng kiểm tra xem bạn có hai phương thức có tên khác nhau và cùng tham số.

Nếu vậy xin vui lòng xóa bất kỳ phương pháp và thử.


2

Tôi đã vấp phải vấn đề này trong khi cố gắng tăng cường các bộ điều khiển WebAPI của mình bằng các hành động bổ sung.

Giả sử bạn sẽ có

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

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

Hiện có hai phương thức thỏa mãn yêu cầu cho / api / bộ điều khiển gây ra vấn đề được mô tả bởi TS.

Tôi không muốn thêm các tham số "giả" vào các hành động bổ sung của mình để tôi xem xét các hành động mặc định và đưa ra:

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

cho phương thức đầu tiên kết hợp với liên kết tuyến "kép":

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

Lưu ý rằng mặc dù không có tham số "hành động" trong mẫu tuyến đầu tiên, rõ ràng bạn vẫn có thể định cấu hình hành động mặc định cho phép chúng tôi tách định tuyến của các cuộc gọi WebAPI "bình thường" và các cuộc gọi sang hành động bổ sung.


2

Trong trường hợp của tôi, mọi thứ đều đúng

1) Cấu hình web được cấu hình đúng 2) Tiền tố tuyến và thuộc tính tuyến là phù hợp

Tôi vẫn nhận được lỗi. Trong trường hợp thuộc tính "Tuyến đường" của tôi (bằng cách nhấn F12) đã trỏ đến System.Web.MVc chứ không phải System.Web.Http gây ra sự cố.


Câu trả lời này đã giúp tôi rất nhiều!
tvb108108

1

Bạn có thể thêm [Route("api/[controller]/[action]")]vào lớp điều khiển của bạn.

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

0

Tôi biết đó là một câu hỏi cũ, nhưng đôi khi, khi bạn sử dụng các tài nguyên dịch vụ như từ AngularJS để kết nối với WebAPI, hãy đảm bảo rằng bạn đang sử dụng đúng tuyến đường, lỗi khác sẽ xảy ra.


0

Đảm bảo rằng bạn KHÔNG trang trí các phương thức Trình điều khiển của mình cho các hành động GET | PUT | POST | DELETE mặc định với thuộc tính [HttpPost / Put / Get / Delete]. Tôi đã thêm tính năng này vào hành động điều khiển vanilla Post của tôi và nó đã gây ra 404.

Hy vọng điều này sẽ giúp được ai đó vì nó có thể rất bực bội và khiến tiến độ bị đình trệ.


0

Ví dụ => TestContoder

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

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

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

Nếu bạn chỉ có thể thay đổi tệp WebApiConfig.cs.

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

Đó là nó :)

Và kết quả: nhập mô tả hình ảnh ở đây


0

Bạn đã thử như thế nào:

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

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

1
Điều này sẽ không biên dịch trong các dự án không phải .NET, vì HttpGetthuộc tính không có hàm tạo chấp nhận đối số chuỗi.
Hoppeduppeanut
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.