2013-01-21 32 views
8

Dường như có một logic mặc định tích hợp cho Web API để sử dụng HTTP Verb làm tên hành động nếu không có hành động nào được cung cấp trong URL. Ví dụ, tôi có tuyến đường này:Làm cách nào để sửa đổi các tuyến API Web mặc định của khung công tác?

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

Và đây là hành động của tôi:

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

    [ActionName("current")] 
    public IEnumerable<Conference> GetCurrent() 
    { 
     ... 
    } 

Khi tôi đi đến ~/Hội Nghị với một động từ GET, nó sẽ đưa bạn đến "Nhận()" hoạt động. Nếu sử dụng động từ POST, nó sẽ đưa bạn đến "Post ([FromBody] Conference value)" action ... và vv. Có một mâu thuẫn mặc dù khi bạn cố gắng để đi đến ~/Hội Nghị/GetCurrent (mặc dù tôi có [ActionName ("hiện tại")] trên đầu trang):

Nhiều hoạt động đã được tìm thấy phù hợp với yêu cầu: Hệ thống .Collections.Generic.IEnumerable 1[MyApp.Models.Conference] Get() on type MyApp.Api.ConferencesController System.Collections.Generic.IEnumerable 1 [MyApp.Models.Conference] GetCurrent() trên kiểu MyApp.Api.ConferencesController

Điều này có nghĩa khuôn khổ đang sử dụng StartsWith thay vì bình đẳng để xác định một hành động mặc định. Ngoài ra, nó bỏ qua thuộc tính ActionName khi kết hợp động từ với hành động.

Câu hỏi của tôi là làm cách nào để tôi thực hiện hành động mặc định của khung làm khớp chính xác với động từ, thay vì sử dụng logic StartsWith? Một động từ GET chỉ phù hợp với hành động Get(), chứ không phải Get(), GetCurrent() GetPast(), vv (đặc biệt khi nó bỏ qua thuộc tính ActionName).

EDIT Để đơn giản, tôi chỉ hiển thị một trong các tuyến đường ở trên. Tôi nghĩ rằng nó có thể giúp đỡ nếu tôi hiển thị tất cả các tuyến đường của tôi mà vẫn còn trong dự thảo. Tôi cố gắng để có được một API REST làm việc hoàn toàn trong khi vẫn để lại chỗ cho thêm hành động tùy chỉnh của riêng tôi:

public static void Register(HttpConfiguration config) 
    { 
     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerActionId", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: null, 
      constraints: new { action = @"^[a-zA-Z]+$", id = @"^\d+$" } // action must start with character 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerActionName", 
      routeTemplate: "api/{controller}/{action}/{name}", 
      defaults: null, 
      constraints: new { action = @"^[a-zA-Z]+$", name = @"^[a-zA-Z]+$" } // action and name must start with character 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerId", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: null, 
      constraints: new { id = @"^\d+$" } // id must be all digits 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerAction", 
      routeTemplate: "api/{controller}/{action}", 
      defaults: null, 
      constraints: new { action = @"^[a-zA-Z]+$" } // action must start with character 
     ); 

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

CẬP NHẬT Dường như thêm contraints HTTP động từ giúp:

 config.Routes.MapHttpRoute(
      name: "DefaultApiControllerGet", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Get" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) } 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerPost", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Post" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) } 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerPut", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Put" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Put) } 
     ); 

     config.Routes.MapHttpRoute(
      name: "DefaultApiControllerDelete", 
      routeTemplate: "api/{controller}", 
      defaults: new { action = "Delete" }, 
      constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Delete) } 
     ); 

Trả lời

7

EDIT : Vì bạn đã thực hiện chỉnh sửa lớn cho câu hỏi, tôi cần thay đổi câu trả lời:

Tóm lại - điều này sẽ không bao giờ làm việc với hộp với Web API, bởi vì nó sẽ theo mặc định cử hành động:

  1. dựa trên tên hành động nếu {action} là một phần của dữ liệu đường
  2. dựa trên HTTP động từ

Tuy nhiên, hai cách tiếp cận những không thể được trộn lẫn trong một bộ điều khiển đơn, vì vậy bạn sẽ không thể gửi các hành động bằng cả hai cách tiếp cận từ một bộ điều khiển duy nhất (đó là những gì bạn đang cố gắng làm).

Bạn có ba cách để sửa lỗi này:

  1. rework nguồn lực của bạn, do đó bạn có những cái riêng biệt cho hành động tên cử và disptaching động từ dựa trên (đó là xa lý tưởng)

  2. đăng ký các tuyến đường thủ công cho mọi tuyến đường lồng nhau. Bằng cách này, bạn tiếp tục gửi đi bằng động từ HTTP, nhưng định tuyến chỉ rõ một hành động cụ thể. Bạn có thể sử dụng một cái gì đó như AttributeRouting (https://github.com/mccalltd/AttributeRouting) để đơn giản hóa điều này. Nhược điểm rõ ràng là bạn kết thúc với - một cách hiệu quả - một tuyến đường cho mỗi hành động

  3. Thực hiện một mới IActionSelector cho phép bạn kết hợp cả điều khiển dựa trên hành động và dựa trên một bộ điều khiển. Đây là giải pháp "cấp thấp nhất", nhưng có vẻ giống như một thứ bạn muốn làm. Tôi đăng một hương tuần trước - http://www.strathweb.com/2013/01/magical-web-api-action-selector-http-verb-and-action-name-dispatching-in-a-single-controller/

+0

Đối với một API REST, tôi vẫn sẽ cần phải nhận được ~/Hội Nghị vẫn làm việc dù – Basem

+0

chỉnh sửa: ok bây giờ mà bạn đăng tải tất cả các tuyến đường của bạn, hình ảnh rõ ràng hơn nhiều;) –

+0

Bài viết tuyệt vời, thx! Ngoài ra AttributeRouting âm thanh hứa hẹn nhưng có vẻ như hiệu suất API Web và tính năng bộ nhớ đệm không được thừa hưởng. – Basem

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