Open steve-jansen opened 11 years ago
I noticed that we might want to override XmlDocProvider::GetDocumentation
to return the fully qualified member name instead of the summary documentation to ensure a unique name that is consistent across all route variations. Not sure if this is a good idea or not.
I also think we can be opinionated that the route template with the fewest querystring parameters is the most specific (and best) route template to use.
We can also iterate through the Collection<ApiDescription>
to find all duplicates within the ApiDocumentation::Documentation member. We should prefer ApiDescription::Route
values that don't match the default route.
Alternatively, we can use the first match in GlobalConfiguration.Configuration.Routes
, since the WebAPI runtime will use the first match found in this collection. So, use the first route that matches, based on priority. Don't use the lower priority routes as the RelativePath.
Another final option is instead of using ActionDescription::RelativePath
as the category name, we could use the Controller Name on the ActionDescription::ControllerDescription::ControllerName
value. Or, parse the route tempate and stop at the first {}
value after replacing the {controller}
and {action}
params and prepending ActionDescription::SupportedHttpMethods
I guess this behavior is due to the APIExplorer.ApiDescriptions()
and I think it is working perfectly. It will try to get all possible route combinations based on the routes defined.
Here we have declared 3 api routes,
configuration.Routes.MapHttpRoute(
name: "Custom route for linking a pet to a user",
routeTemplate: "api/Pet/{id}/User/{userId}",
defaults: new { controller = "Pet", action = "PutUser", userId = RouteParameter.Optional },
constraints: new { id = @"\d+", userId = @"\d*" });
configuration.Routes.MapHttpRoute(
name: "Controller Actions That Are Not HTTP Verbs",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { action = @"\D+", id = @"\d*", });
configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
If we consider the route for action.
[HttpPut]
[ActionName("PutExport")]
public HttpResponseMessage Put(int id, int? userId = null)
{
return Request.CreateResponse(HttpStatusCode.NoContent);
}
it can be reached by below combination,
api/Pet/PutExport/{id}?userId={userId} // Route 2
api/Pet/{id}?user={userId} // Route 3
In Route it is defined as PutUser but action name is PutExport. It we make them in sync, by changing either, it will start matching 1st route, so valid routes will be
api/Pet/{id}/User/{userId} // Route 1
api/Pet/PutUser/{id}?userId={userId} // Route 2
api/Pet/{id}?userId={userId} // Route 3
Overview Swagger.Net gets confused with WebAPI routes using action names that are not standard HTTP verbs. This is necessary to route the same HTTP verb, like GET, to multiple controller actions.
This is a corrolary of issue #5.
Steps To Reproduce
Actual Results Routes to controller actions using custom route templates fall back to using the default API route, like
PUT /api/Pet/PutExport/{id}?userId={userId}
instead of the customPUT /api/Pet/{id}/User/{userId}
Expected Results Swagger should document the custom route only
PUT /api/Pet/{id}/User/{userId}
Example Routing Config configuration.Routes.MapHttpRoute( name: "Custom route for linking a pet to a user", routeTemplate: "api/Pet/{id}/User/{userId}", defaults: new { controller="Pet", action="PutUser", userId = RouteParameter.Optional }, constraints: new { id = @"\d+", userId = @"\d*" });
Screenshot