9

Bei der Verwendung von ASP.NET Web API Hilfe Page und die damit verbundene MVC.ApiExplorer Ich habe gültige Routen, die über http zugänglich sind noch nicht durch ApiExplorer entdeckt. Diese Routen werden nur gefunden, wenn eine allgemeine Routing-Regel verwendet wird. Die Verwendung einer spezifischeren Regel (in Verbindung mit der allgemeinen Regel) scheint die Routen vom ApiExplorer zu verbergen.Gültige Routen entdeckt nicht durch MVC.ApiExplorer

In einem Beispielfall von drei Regeln beziehen sich zwei Wege auf eine GET- und eine POST-Aktion auf einer Controller-Methode, die keine Abfrageparameter verwenden, gehen MIA.

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

Wenn eine Routing-Regel der Verwendung

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

Die Routen werden in geeigneter Weise durch Api Explorer entdeckt als

  • POST: api/SomeController
  • GET: api/SomeController
  • GET: api/SomeController/{id}

noch bei der Zugabe der weniger generisch und sinnvolle Regel

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 gibt nur

  • GET: api/somecontroller/{id}

Was ist die Ursache einige meiner Routen nicht zu finden?

EDIT Link to Issue Report on ApiExplorer project page

Antwort

5

Ich glaube, was Sie sehen, ein bekannter Fehler mit ApiExplorer ist. Was passiert ist, dass der ApiExplorer durch jede Route in der Routensammlung geht und überprüft, ob der Controller und seine Aktionen gelöst werden können.

In diesem Fall kann zum Beispiel die Aktion "GetById" von beiden oben genannten Routen erkundet werden, die ApiExplorer fälschlicherweise als Ursache für einen Konflikt aufgrund mehrdeutiger Übereinstimmung betrachtet und versucht, doppelte Aktionen herauszufiltern, die in diesem Fall bewirkt, dass alle Aktionen gefiltert/entfernt werden. Da dieser Fehler in ApiExplorer (der Teil des Haupt-WebAPI-Kerns ist) liegt, fürchte ich, dass wir ihn in absehbarer Zeit nicht beheben können.

+0

Ich habe gerade verifiziert, die "ApiDefault" -Regel zu entfernen und die "ApiSomeControllerDefault" -Regel zu lassen, macht die einmal verborgenen Routen für ApiExplorer verfügbar. – rheone

+0

Wie haben Sie die ApiDefault-Regel entfernt? – user3654055

5

Während dieser Fehler nicht von ASP.NET Web API-Team behoben wird, verwende ich meine eigene dumme Lösung.

Meine Erweiterungsmethode für IApiExplorer tut die gleichen Dinge wie original ApiDescriptions Implementierung in ApiExplorer Klasse, aber anstatt Entfernen von doppelten Aktionen für verschiedene Routen, es gibt nur Aktionen mit unterschiedlicher ID (HTTP-Methode + Strecke). Daher werden alle angegebenen Aktionen zurückgegeben, unabhängig von der Anzahl der Routen.

Und ja, es verwendet schamlos Reflexion, um die private Methode zu nennen.

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

Es ist einfach zu bedienen:

var apiDescriptions = apiExplorer.GetAllApiDescriptions(httpConfig); 

HttpConfiguration Parameter für Testbarkeit hinzugefügt. Wenn Sie sich nicht darum kümmern, entfernen Sie den Parameter und verwenden Sie einfach GlobalConfiguration.HttpConfiguration in der Erweiterungsmethode direkt.

+0

Vielen Dank. Diese Antwort löste mein Problem nach so viel Kampf mit dem Rahmen !!! –