asp.net - net - Enrutamiento de API web-api/{controller}/{action}/{id} "dysfunctions" api/{controller}/{id}
web api 2 route config (2)
Tengo la ruta predeterminada en Global.asax:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
Quería poder orientarme a una función específica, así que creé otra ruta:
RouteTable.Routes.MapHttpRoute(
name: "WithActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
Entonces, en mi controlador, tengo:
public string Get(int id)
{
return "object of id id";
}
[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
return new string[] { "byCategory1", "byCategory2" };
}
Llamar a .../api/records/bycategoryid/5
me dará lo que quiero. Sin embargo, llamar .../api/records/1
me dará el error
Se encontraron varias acciones que coinciden con la solicitud: ...
Entiendo por qué: las rutas solo definen qué URL son válidas, pero cuando se trata de la función, tanto Get(int id)
como ByCategoryId(int id)
coinciden con api/{controller}/{id}
, que es lo que confunde el marco.
¿Qué debo hacer para que funcione la ruta predeterminada de la API y conservar la que tiene {action}
? Pensé en crear un controlador diferente llamado RecordByCategoryIdController
para que coincida con la ruta API predeterminada, para lo cual solicitaría .../api/recordbycategoryid/5
. Sin embargo, considero que es una solución "sucia" (por lo tanto, insatisfactoria). He buscado respuestas sobre esto y ningún tutorial sobre el uso de una ruta con {action}
incluso menciona este problema.
El motor de ruta usa la misma secuencia en la que agrega reglas. Una vez que obtiene la primera regla coincidente, dejará de verificar otras reglas y tomará esto para buscar controlador y acción.
Entonces, debes:
Ponga sus reglas específicas por delante de sus reglas generales (como por defecto), lo que significa utilizar
RouteTable.Routes.MapHttpRoute
para asignar primero "WithActionApi", luego "DefaultApi".Elimine los
defaults: new { id = System.Web.Http.RouteParameter.Optional }
parámetrodefaults: new { id = System.Web.Http.RouteParameter.Optional }
de su regla "WithActionApi" porque una vez que la identificación es opcional, la URL como "/ api / {part1} / {part2}" nunca entrará en " DefaultApi ".Agregue una acción nombrada a su "DefaultApi" para indicarle al motor de la ruta qué acción debe ingresar. De lo contrario, una vez que tenga más de una acción en su controlador, el motor no sabrá cuál usar y arrojará "Se encontraron varias acciones que coinciden con la solicitud: ...". Luego, para hacer que coincida con su método Get, use ActionNameAttribute .
Entonces su ruta debería tener esto:
// Map this rule first
RouteTable.Routes.MapRoute(
"WithActionApi",
"api/{controller}/{action}/{id}"
);
RouteTable.Routes.MapRoute(
"DefaultApi",
"api/{controller}/{id}",
new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
);
Y tu controlador:
[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public string Get(int id)
{
return "object of id id";
}
[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
return new string[] { "byCategory1", "byCategory2" };
}
Puede resolver su problema con la ayuda del enrutamiento de atributos
Controlador
[Route("api/category/{categoryId}")]
public IEnumerable<Order> GetCategoryId(int categoryId) { ... }
URI en jquery
api/category/1
Configuración de ruta
using System.Web.Http;
namespace WebApplication
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown.
}
}
}
y su enrutamiento predeterminado funciona como enrutamiento predeterminado basado en convenciones
Controlador
public string Get(int id)
{
return "object of id id";
}
URI en Jquery
/api/records/1
Configuración de ruta
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Revise el artículo para más información Enrutamiento de atributos y enrutamiento basado en convenciones aquí y this