Ich habe die Standardroute in Global.asax:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
Ich wollte in der Lage sein, auf eine bestimmte Funktion abzuzielen, deshalb habe ich eine andere Route erstellt:
RouteTable.Routes.MapHttpRoute(
name: "WithActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
Also habe ich in meinem Controller:
public string Get(int id)
{
return "object of id id";
}
[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
return new string[] { "byCategory1", "byCategory2" };
}
Wenn ich .../api/records/bycategoryid/5
Anrufe, bekomme ich, was ich will. Wenn ich jedoch .../api/records/1
Aufrufe, erhalte ich den Fehler
Es wurden mehrere Aktionen gefunden, die der Anfrage entsprechen: ...
Ich verstehe, warum das so ist - die Routen definieren nur, welche URLs gültig sind, aber wenn es um die Funktionsübereinstimmung geht, stimmen sowohl Get(int id)
als auch ByCategoryId(int id)
mit api/{controller}/{id}
Überein verwirrt den Rahmen.
Was muss ich tun, damit die Standard-API-Route wieder funktioniert und die mit {action}
Beibehalten wird? Ich dachte daran, einen anderen Controller mit dem Namen RecordByCategoryIdController
zu erstellen, der der Standard-API-Route entspricht, für die ich .../api/recordbycategoryid/5
Anfordern würde. Ich finde jedoch, dass dies eine "schmutzige" (also unbefriedigende) Lösung ist. Ich habe nach Antworten zu diesem Thema gesucht und kein Tutorial zur Verwendung einer Route mit {action}
Erwähnt dieses Problem.
Das Routenmodul verwendet die gleiche Reihenfolge, in der Sie Regeln hinzufügen. Sobald es die erste übereinstimmende Regel erhält, hört es auf, andere Regeln zu überprüfen und sucht nach Controller und Aktion.
Deshalb solltest du:
Stellen Sie Ihre spezifischen Regeln vor Ihre allgemeinen Regeln (wie die Standardregeln), was bedeutet, dass Sie RouteTable.Routes.MapHttpRoute
zuerst "WithActionApi", dann "DefaultApi" zuordnen.
Entferne das defaults: new { id = System.Web.Http.RouteParameter.Optional }
-Parameter Ihrer "WithActionApi" -Regel, da eine einmal optionale ID die URL "/ api/{part1}/{part2}" niemals in "DefaultApi" einfügt.
Fügen Sie Ihrem "DefaultApi" eine benannte Aktion hinzu, um dem Routenmodul mitzuteilen, welche Aktion eingegeben werden soll. Wenn Sie mehr als eine Aktion in Ihrem Controller haben, weiß die Engine nicht, welche verwendet werden soll, und gibt den Befehl "Es wurden mehrere Aktionen gefunden, die der Anforderung entsprechen: ..." aus. Verwenden Sie anschließend ein ActionNameAttribute , damit es mit Ihrer Get-Methode übereinstimmt.
Ihre Route sollte also so aussehen:
// 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 }
);
Und dein Controller:
[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" };
}
Sie können Ihr Problem mit Hilfe des Attribut-Routings lösen
Controller
[Route("api/category/{categoryId}")]
public IEnumerable<Order> GetCategoryId(int categoryId) { ... }
URI in Abfrage
api/category/1
Routenkonfiguration
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.
}
}
}
und Ihr Standardrouting funktioniert als standardmäßiges konventionelles Routing
Controller
public string Get(int id)
{
return "object of id id";
}
URI in Jquery
/api/records/1
Routenkonfiguration
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 }
);
}
}
Weitere Informationen finden Sie im Artikel Attribut-Routing und erfindungsbezogenes Routing hier & this
Der mögliche Grund kann auch sein, dass Sie Controller nicht von ApiController geerbt haben. Es hat eine Weile gedauert, bis ich dasselbe verstanden habe.
Versuche dies.
public class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var json = config.Formatters.JsonFormatter;
json.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
config.Formatters.Remove(config.Formatters.XmlFormatter);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional , Action =RouteParameter.Optional }
);
}
}
Um die Routen zu unterscheiden, fügen Sie eine Einschränkung hinzu, dass die ID numerisch sein muss:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
constraints: new { id = @"\d+" }, // Only matches if "id" is one or more digits.
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);