2012-10-29 29 views
8

Tôi có một bộ điều khiển Web API với các hành động sau:Nhiều hành động cho HttpVerb cùng

[HttpPut] 
    public string Put(int id, JObject data) 

    [HttpPut, ActionName("Lock")] 
    public bool Lock(int id) 

    [HttpPut, ActionName("Unlock")] 
    public bool Unlock(int id) 

Và các tuyến đường sau ánh xạ:

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

Khi tôi thực hiện các yêu cầu sau đây mọi thứ hoạt động như mong đợi :

PUT /api/items/Lock/5 
PUT /api/items/Unlock/5 

Nhưng khi tôi cố gắng yêu cầu:

PUT /api/items/5 

tôi nhận được ngoại lệ sau đây:

Multiple actions were found that match the request: 
    Put(int id, JObject data) 
    Lock(int id) 
    Unlock(int id) 

Tôi đã thử thêm một tên hành động trống để các tuyến đường mặc định nhưng điều đó không giúp:

[HttpPut, ActionName("")] 
public string Put(int id, JObject data) 

Bất kỳ ý tưởng làm thế nào tôi có thể kết hợp mặc định Định tuyến RESTful với tên hành động tùy chỉnh?

EDIT: Cơ chế định tuyến không bị nhầm lẫn bởi lựa chọn bộ điều khiển. Nó bị nhầm lẫn bởi sự lựa chọn của hành động trên một bộ điều khiển duy nhất. Những gì tôi cần là để phù hợp với hành động mặc định khi không có hành động nào được chỉ định. Hy vọng rằng làm rõ mọi thứ.

+0

Hình như điều này có thể trả lời Q của bạn: http://stackoverflow.com/questions/9499794/single-controller -with-multiple-get-methods-in-asp-net-web-api –

+0

@GiscardBiamby Cảm ơn bạn đã liên kết, tôi xem qua một lần thử. –

+0

@GiscardBiamby Bạn chắc chắn đã chỉ cho tôi đúng hướng. Câu trả lời này: http://stackoverflow.com/a/12185249/99373 đã giúp tôi tìm ra những gì tôi cần làm và nó đã hoạt động! Nếu bạn muốn có tín dụng, hãy đăng câu trả lời và tôi sẽ chấp nhận. –

Trả lời

2

Với sự giúp đỡ của Giscard Biamby, tôi thấy this answer mà chỉ cho tôi đi đúng hướng.Cuối cùng, để giải quyết vấn đề cụ thể này, tôi đã làm nó theo cách này:

routes.MapHttpRoute(
    name: "ApiPut", 
    routeTemplate: "api/{controller}/{id}", 
    defaults: new { action = "Put" }, 
    constraints: new { httpMethod = new HttpMethodConstraint("Put") } 
); 

Cảm ơn @GiscardBiamby

-3

Thứ nhất, loại bỏ [HttpPut, ActionName("")] và sau đó sửa đổi tuyến đường của bạn để này

config.Routes.MapHttpRoute(
    name: "Api", 
    routeTemplate: "api/{controller}/{id}", 
    defaults: new { id = RouteParameter.Optional }, 
    constraints: new { id = @"^[0-9]+$" } 
    ); 
+0

Thật không may, tôi không thể làm điều đó bởi vì tôi có bộ điều khiển khác với chuỗi/guid Ids. Ràng buộc "số" sẽ phá vỡ chúng. –

+0

Bạn có thể xác định nhiều tuyến đường. Chỉ cần thay đổi mã trên để nhắm mục tiêu bộ điều khiển cụ thể của bạn, tức là 'routesTemplate:" api/items/{id} ", mặc định: new {controller =" items "...' –

+0

Vui lòng xem các chỉnh sửa của tôi ở trên. Cơ chế định tuyến tìm bộ điều khiển không có vấn đề gì. Vấn đề là nó cho rằng cả ba hành động đều phù hợp với yêu cầu: 'PUT/api/items/5'. Những gì tôi cần là để phù hợp với hành động mặc định khi không có hành động nào được chỉ định. Hy vọng rằng làm rõ mọi thứ. –

6

Đây là một lỗi mong đợi từ bộ chọn hành động mặc định là ApiControllerActionSelector. Về cơ bản, bạn có ba phương thức hành động tương ứng với động từ HTTP Put. Cũng nên nhớ rằng chọn hành động mặc định coi các loại tham số hành động đơn giản đó là tất cả các loại NET nguyên thủy, các loại đơn giản nổi tiếng (System.String, System.DateTime, System.Decimal, System.Guid, System.DateTimeOffset, System.TimeSpan) và tiềm ẩn các loại đơn giản (ví dụ: Nullable<System.Int32>).

Là một giải pháp cho vấn đề của bạn tôi sẽ tạo ra hai bộ điều khiển cho những người như sau:

public class FooController : ApiController { 

    public string Put(int id, JObject data) 
} 

public class FooRPCController : ApiController { 

    [HttpPut] 
    public bool Lock(int id) 

    [HttpPut] 
    public bool Unlock(int id) 
} 

các tuyến đường sẽ trông giống như dưới đây:

routes.MapHttpRoute(
    name: "ApiAction", 
    routeTemplate: "api/Foo/{action}/{id}", 
    defaults: new { controller = "FooRPC" } 
); 

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

Mặt khác (không hoàn toàn liên quan cho chủ đề của bạn), tôi có ba bài đăng trên blog về lựa chọn hành động, đặc biệt là với các thông số kiểu phức tạp. Tôi khuyến khích bạn kiểm tra chúng ra vì chúng có thể cung cấp cho bạn một vài quan điểm hơn:

+0

Vì tò mò, đây có phải là trường hợp "Không thể thực hiện theo cách đó" được không? Tôi thực sự muốn giữ những thứ trong cùng một bộ điều khiển vì nó làm cho ứng dụng của tôi dễ bảo trì hơn. Có nhiều bộ điều khiển khác trong ứng dụng cần được sửa đổi để hỗ trợ việc triển khai được đề xuất này. –

+0

@adaptive Xem câu trả lời cập nhật của tôi. Nếu bạn quản lý để giữ cho bộ chọn hành động hạnh phúc, chắc chắn bạn có thể xử lý chúng trong một bộ điều khiển. – tugberk

+0

Cảm ơn câu trả lời sâu sắc. Vì vậy, có lẽ tôi có thể viết một 'ActionSelector' tùy chỉnh để giải quyết vấn đề? –

Các vấn đề liên quan