9

Khi sử dụng ASP.NET Web API Trợ giúp Trang và liên quan MVC.ApiExplorer Tôi có tuyến đường hợp lệ mà có thể truy cập thông qua http chưa không được phát hiện bởi ApiExplorer. Các tuyến đường này chỉ được tìm thấy khi sử dụng quy tắc định tuyến chung. Việc sử dụng một quy tắc cụ thể hơn (kết hợp với quy tắc chung) dường như ẩn các tuyến từ ApiExplorer.tuyến đường hợp lệ không được phát hiện bởi MVC.ApiExplorer

Trong trường hợp ví dụ về ba quy tắc, hai tuyến liên quan đến hành động GET và POST trên phương thức điều khiển không có tham số truy vấn nào đi tới MIA.

public class SomeControllerController : ApiController 
{ 
    [HttpPost] public HttpResponseMessage Post(PostObject value) { ... } 
    [HttpGet] public IEnumerable<DisplayObject> GetAll() { ... } 
    [HttpGet] public DisplayObject GetById(string id) { ... } 
} 

Khi sử dụng một quy tắc định tuyến của

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

Các tuyến đường được phát hiện một cách thích hợp bởi Api Explorer như

  • POST: api/SomeController
  • GET: api/SomeController
  • NHẬN: api/SomeController/{id}

chưa khi thêm các quy tắc ít chung chung và có ý nghĩa hơn

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

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

Api Explorer chỉ trả

  • GET: api/somecontroller/{id}

gì đang gây ra một số tuyến đường của tôi không được tìm thấy?

EDIT Link to Issue Report on ApiExplorer project page

Trả lời

5

Tôi tin rằng những gì bạn đang nhìn thấy là một lỗi được biết đến với ApiExplorer. Điều gì đang xảy ra là ApiExplorer đi qua mỗi tuyến đường trong bộ sưu tập tuyến đường và kiểm tra xem bộ điều khiển và hành động của nó có thể được giải quyết hay không.

Trong trường hợp này, ví dụ, các hành động "GetById" có thể được khám phá bởi cả các tuyến đường trên, mà ApiExplorer sai giả định là gây ra một cuộc xung đột do đối sánh mơ hồ và nó cố gắng để lọc ra các hành động trùng lặp, mà trong này trường hợp đang gây ra tất cả các hành động được lọc/xóa. Kể từ khi lỗi này là trong ApiExplorer (là một phần của lõi WebAPI chính), tôi sợ chúng tôi không thể sửa chữa nó bất cứ lúc nào sớm.

+0

Tôi vừa xác minh loại bỏ quy tắc "ApiDefault" và để nguyên tắc "ApiSomeControllerDefault" thực sự làm cho các tuyến ẩn một lần có sẵn cho ApiExplorer. – rheone

+0

Bạn đã xóa quy tắc ApiDefault như thế nào? – user3654055

5

Trong khi lỗi này không được cố định bởi nhóm ASP.NET Web API, tôi đang sử dụng sửa chữa câm của riêng tôi.

phương pháp khuyến nông của tôi cho IApiExplorer đang làm những điều tương tự như ban đầu ApiDescriptions thực hiện trong ApiExplorer lớp, nhưng thay vì loại bỏ những hành động trùng lặp cho tuyến đường khác nhau, nó chỉ trả về những hành động với ID riêng biệt (phương thức HTTP + đường). Vì vậy, nó trả về tất cả các hành động được khai báo, bất kể số lượng tuyến đường.

Và, vâng, nó không biết xấu hổ sử dụng sự phản chiếu để gọi phương thức riêng tư.

public static class WebApiExtensions 
{ 
    public static Collection<ApiDescription> GetAllApiDescriptions(this IApiExplorer apiExplorer, HttpConfiguration httpConfig) 
    { 
     if (!(apiExplorer is ApiExplorer)) 
     { 
      return apiExplorer.ApiDescriptions; 
     } 

     IList<ApiDescription> apiDescriptions = new Collection<ApiDescription>(); 
     var controllerSelector = httpConfig.Services.GetHttpControllerSelector(); 
     var controllerMappings = controllerSelector.GetControllerMapping(); 

     if (controllerMappings != null) 
     { 
      foreach (var route in httpConfig.Routes) 
      { 
       typeof(ApiExplorer).GetMethod("ExploreRouteControllers", 
        bindingAttr: BindingFlags.Instance | BindingFlags.NonPublic, 
        binder: null, 
        types: new[] {typeof(IDictionary<string, HttpControllerDescriptor>), typeof(IHttpRoute), typeof(Collection<ApiDescription>)}, 
        modifiers: null 
       ).Invoke(apiExplorer, new object[] {controllerMappings, route, apiDescriptions}); 
      } 

      apiDescriptions = apiDescriptions 
       .GroupBy(api => api.ID.ToLower()) 
       .Select(g => g.First()) 
       .ToList(); 
     } 

     return new Collection<ApiDescription>(apiDescriptions); 
    } 
} 

Thật dễ dàng để sử dụng:

var apiDescriptions = apiExplorer.GetAllApiDescriptions(httpConfig); 

HttpConfiguration tham số bổ sung cho testability. Nếu bạn không quan tâm đến nó, hãy xóa tham số và chỉ sử dụng trực tiếp phương thức mở rộng một cách trực tiếp GlobalConfiguration.HttpConfiguration.

+0

Cảm ơn bạn rất nhiều. Câu trả lời này giải quyết vấn đề của tôi sau khi chiến đấu rất nhiều với khung! –

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