Es wurden mehrere Aktionen gefunden, die der Anforderung in Web Api entsprechen

243

Ich erhalte immer wieder diesen Fehler, wenn ich versuche, zwei "Get" -Methoden zu verwenden

Es wurden mehrere Aktionen gefunden, die der Anforderung entsprechen: webapi

Ich habe mich nach anderen ähnlichen Fragen auf dem Stapel umgesehen, aber ich verstehe sie nicht.

Ich habe 2 verschiedene Namen und benutze das Attribut "HttpGet"

[HttpGet]
public HttpResponseMessage Summary(MyVm vm)
{
    return null;
}

[HttpGet]
public HttpResponseMessage FullDetails()
{
    return null;
}
chobo2
quelle

Antworten:

485

Ihre Routenkarte sieht wahrscheinlich so aus:

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

Um jedoch mehrere Aktionen mit derselben http-Methode ausführen zu können, müssen Sie webapi über die folgende Route weitere Informationen bereitstellen:

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

Beachten Sie, dass die routeTemplate jetzt eine Aktion enthält. Viele weitere Informationen hier: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

Aktualisieren:

Okay, jetzt, wo ich denke, ich verstehe, wonach Sie hier suchen, ist eine andere Einstellung dazu:

Möglicherweise benötigen Sie den Aktions-URL-Parameter nicht und sollten den Inhalt, nach dem Sie suchen, auf andere Weise beschreiben. Da Sie sagen, dass die Methoden Daten von derselben Entität zurückgeben, lassen Sie einfach die Parameter die Beschreibung für Sie übernehmen.

Zum Beispiel könnten Ihre beiden Methoden in Folgendes umgewandelt werden:

public HttpResponseMessage Get()
{
    return null;
}

public HttpResponseMessage Get(MyVm vm)
{
    return null;
}

Welche Art von Daten übergeben Sie im MyVm-Objekt? Wenn Sie nur Variablen über den URI übergeben können, würde ich vorschlagen, diesen Weg zu gehen. Andernfalls müssen Sie das Objekt im Hauptteil der Anforderung senden, und das ist nicht sehr HTTP von Ihnen, wenn Sie ein GET ausführen (es funktioniert jedoch, verwenden Sie einfach [FromBody] vor MyVm).

Hoffentlich zeigt dies, dass Sie mehrere GET-Methoden in einem einzelnen Controller haben können, ohne den Aktionsnamen oder sogar das Attribut [HttpGet] zu verwenden.

Jed
quelle
Gibt es irgendwelche Vorteile auf die eine oder andere Weise? Wenn ich die sekundäre mache, muss ich nur die HTTP-Aktion auf jede Methode setzen? Ist das der große Nachteil?
Chobo2
3
Ob einer einen Vorteil gegenüber dem anderen hat, hängt wirklich von Ihrem Projekt ab. Wenn Sie eine RESTful-API erstellen, sollten Sie die HTTP-Konventionen (GET, POST, PUT, DELETE ...) verwenden. In diesem Fall ist der erste Block des Routing-Codes der richtige Weg, aber Sie möchten für jede Entität, die Sie über die API verfügbar machen, einen anderen Controller. Aufgrund Ihrer Methodennamen ist dies vermutlich nicht der Fall. Verwenden Sie daher das aussagekräftigere Routing. Wenn Ihre Route die Aktion enthält, möchten Sie das http-Attribut für jede Methode explizit einfügen.
Jed
1
@ chobo2 Warum nicht einfach Methoden verwenden, die im Controller entsprechend benannt sind? GetSummary (MyVm wm) und GetDetails ()
Jed
1
Vielen Dank für Ihre Antwort. Ich habe nur herausgefunden, warum die Routenauflösung nicht funktioniert, obwohl meine beiden Aktionen unterschiedliche Namen hatten. Ich bin wirklich verwirrt darüber, warum nicht nur das Standardverhalten ist (dh warum nicht die Standardroutenvorlage in webapiconfig.cs "{action}" enthält)!
Tejas Sharma
1
@bruno Wenn Sie Bereiche verwenden, können Sie auch 'admin'-spezifische APIs wie diese in AdminAreaRegistration stackoverflow.com/a/9849011/16940
Simon_Weaver
67

Update ab Web API 2.

Mit dieser API-Konfiguration in Ihrer WebApiConfig.cs-Datei:

public static void Register(HttpConfiguration config)
{
    //// Web API routes
    config.MapHttpAttributeRoutes(); //Don't miss this

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = System.Web.Http.RouteParameter.Optional }
    );
}

Sie können unseren Controller folgendermaßen routen:

[Route("api/ControllerName/Summary")]
[HttpGet]
public HttpResponseMessage Summary(MyVm vm)
{
    rturn null;
}

[Route("api/ControllerName/FullDetails")]
[HttpGet]
public HttpResponseMessage FullDetails()
{
    return null;
}

Wobei ControllerName der Name Ihres Controllers ist (ohne "Controller"). Auf diese Weise können Sie jede Aktion mit der oben beschriebenen Route ausführen.

Weitere Informationen: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

Marc Stevenson
quelle
Diese Lösung hat mir sehr gut gefallen. Meine Standardroute ist immer noch dieselbe und ich habe eine "Ausnahmeroute" für die Ausnahmen
Leandro De Mello Fagundes
Sie können die Parameter auch der URL EX zuordnen: [Route ("api / ControllerName / Summary / {vm}")]
nulltron
15

In der Web-API werden (standardmäßig) Methoden basierend auf einer Kombination aus HTTP-Methode und Routenwerten ausgewählt .

MyVmsieht aus wie ein komplexes Objekt, das vom Formatierer aus dem Textkörper gelesen wird, sodass Sie zwei identische Methoden in Bezug auf Routendaten haben (da keiner von beiden Parameter aus der Route enthält) - was es dem Dispatcher ( IHttpActionSelector) unmöglich macht , mit dem entsprechenden übereinzustimmen .

Sie müssen sie entweder durch Querystring- oder Routenparameter unterscheiden, um Mehrdeutigkeiten aufzulösen.

Filip W.
quelle
14

Nachdem Sie viel im Internet gesucht und versucht haben, das am besten geeignete Formular für die Routing-Karte zu finden, haben Sie Folgendes gefunden

config.Routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id =RouteParameter.Optional }, new { id = @"\d+" });
config.Routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");

Diese Zuordnung gilt sowohl für die Zuordnung von Aktionsnamen als auch für die grundlegende http-Konvention (GET, POST, PUT, DELETE).

Moatasem Bakri
quelle
9
Für mich funktionierte dies, aber erst nachdem ich die Reihenfolge der Routen in der
Fredrik Stolpe
genau ist wichtig , um hier
AT
5

Ohne Aktionen wären die Optionen:

  1. Verschieben Sie eine der Methoden auf einen anderen Controller, damit sie nicht zusammenstoßen.

  2. Verwenden Sie nur eine Methode, die den Parameter übernimmt, und rufen Sie die andere Methode aus Ihrem Code auf, wenn sie null ist.

Joanna Derks
quelle
Es könnte eine Lösung sein, aber sowieso keine optimale +1 von meiner Seite :)
Satish Kumar V
4

Diese Lösung hat bei mir funktioniert.

Bitte platzieren Sie Route2 zuerst in WebApiConfig. Fügen Sie außerdem vor jeder Methode HttpGet und HttpPost hinzu und fügen Sie den Controller-Namen und den Methodennamen in die URL ein.

WebApiConfig =>

config.Routes.MapHttpRoute(
           name: "MapByAction",
           routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional });
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });

Controller =>

public class ValuesController : ApiController
{

    [HttpPost]
    public string GetCustomer([FromBody] RequestModel req)
    {
        return "Customer";
    }

    [HttpPost]
    public string GetCustomerList([FromBody] RequestModel req)
    {
        return "Customer List";
    }
}

URL =>

http://localhost:7050/api/Values/GetCustomer

http://localhost:7050/api/Values/GetCustomerList
Alan Rezende
quelle
4

Dies ist die Antwort für alle, die wissen, dass alles korrekt ist und 50 Mal überprüft haben .....

Stellen Sie sicher, dass Sie nicht wiederholt suchen RouteConfig.cs.

Die Datei, die Sie bearbeiten möchten, heißt WebApiConfig.cs

Außerdem sollte es wahrscheinlich genau so aussehen:

using System.Web.Http;

namespace My.Epic.Website
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
          config.MapHttpAttributeRoutes();

          // api/Country/WithStates
          config.Routes.MapHttpRoute(
            name: "ControllerAndActionOnly",
            routeTemplate: "api/{controller}/{action}",
            defaults: new { },
            constraints: new { action = @"^[a-zA-Z]+([\s][a-zA-Z]+)*$" });

          config.Routes.MapHttpRoute(
            name: "DefaultActionApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
          );
    }
    }
}

Ich hätte mir ungefähr 3 Stunden sparen können.

CarComp
quelle
1
Danke, du hast mir ungefähr 3 Stunden
gespart
3

Ich habe festgestellt, dass ich bei zwei Get-Methoden, einer ohne Parameter und einer mit einem komplexen Typ als Parameter, denselben Fehler erhalten habe. Ich habe dieses Problem gelöst, indem ich als ersten Parameter einen Dummy-Parameter vom Typ int mit dem Namen Id hinzugefügt habe, gefolgt von meinem komplexen Typparameter. Ich habe dann den komplexen Typparameter zur Routenvorlage hinzugefügt. Folgendes hat bei mir funktioniert.

Zuerst bekommen:

public IEnumerable<SearchItem> Get()
{
...
}

Zweitens bekommen:

public IEnumerable<SearchItem> Get(int id, [FromUri] List<string> layers)
{
...
}

WebApiConfig:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}/{layers}",
    defaults: new { id = RouteParameter.Optional, layers RouteParameter.Optional }
);
Andrew Terwiel
quelle
3

Dies ist aufgrund der Verwendung des MVC-Controllers anstelle des Web-API-Controllers möglich. Überprüfen Sie den Namespace im Web-API-Controller wie folgt

using System.Net;
using System.Net.Http;
using System.Web.Http;

Wenn der Namespace wie folgt lautet, wird beim Aufrufen der Web-API-Controller-Methode der obige Fehler angezeigt

using System.Web;
using System.Web.Mvc;
Ujwal Khairnar
quelle
2

Bitte überprüfen Sie, ob Sie zwei Methoden haben, die den unterschiedlichen Namen und die gleichen Parameter haben.

Wenn ja, löschen Sie bitte eine der Methoden und versuchen Sie es.

Ramesh
quelle
2

Ich bin auf dieses Problem gestoßen, als ich versucht habe, meine WebAPI-Controller mit zusätzlichen Aktionen zu erweitern.

Angenommen, Sie hätten

public IEnumerable<string> Get()
{
    return this.Repository.GetAll();
}

[HttpGet]
public void ReSeed()
{
    // Your custom action here
}

Es gibt jetzt zwei Methoden, die die Anforderung für / api / controller erfüllen, wodurch das von TS beschriebene Problem ausgelöst wird.

Ich wollte meinen zusätzlichen Aktionen keine "Dummy" -Parameter hinzufügen, also habe ich mir Standardaktionen angesehen und mir Folgendes ausgedacht:

[ActionName("builtin")]
public IEnumerable<string> Get()
{
    return this.Repository.GetAll();
}

für die erste Methode in Kombination mit der "dualen" Routenbindung:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { action = "builtin", id = RouteParameter.Optional },
    constraints: new { id = @"\d+" });

config.Routes.MapHttpRoute(
    name: "CustomActionApi",
    routeTemplate: "api/{controller}/{action}");

Beachten Sie, dass Sie, obwohl die erste Routenvorlage anscheinend keinen "Aktions" -Parameter enthält, dennoch eine Standardaktion konfigurieren können, mit der wir das Routing der "normalen" WebAPI-Aufrufe und der Aufrufe an die zusätzliche Aktion trennen können.

Bjørn van Dommelen
quelle
2

In meinem Fall war alles richtig

1) Die Webkonfiguration wurde ordnungsgemäß konfiguriert. 2) Das Routenpräfix und die Routenattribute waren ordnungsgemäß

Trotzdem bekam ich den Fehler. In meinem Fall zeigte das Attribut "Route" (durch Drücken von F12) auf System.Web.MVc, nicht jedoch auf System.Web.Http, was das Problem verursachte.

Hemanth Vatti
quelle
Diese Antwort hat mir sehr geholfen!
tvb108108
1

Sie können [Route("api/[controller]/[action]")]Ihrer Controller-Klasse hinzufügen .

[Route("api/[controller]/[action]")]
[ApiController]
public class MySuperController : ControllerBase
{
 ...
}
emert117
quelle
0

Ich weiß, dass es eine alte Frage ist, aber manchmal, wenn Sie Serviceressourcen wie AngularJS verwenden, um eine Verbindung zu WebAPI herzustellen, stellen Sie sicher, dass Sie die richtige Route verwenden. Andernfalls tritt dieser Fehler auf.

Suresh Kaushik
quelle
0

Stellen Sie sicher, dass Sie Ihre Controller-Methoden NICHT für die Standardaktionen GET | PUT | POST | DELETE mit dem Attribut [HttpPost / Put / Get / Delete] dekorieren. Ich hatte dieses Attibute zu meiner Vanilla Post-Controller-Aktion hinzugefügt und es verursachte einen 404.

Ich hoffe, dies hilft jemandem, da es sehr frustrierend sein und den Fortschritt zum Stillstand bringen kann.

Komm herein
quelle
0

Zum Beispiel => TestController

        [HttpGet]
        public string TestMethod(int arg0)
        {
            return "";
        }

        [HttpGet]
        public string TestMethod2(string arg0)
        {
            return "";
        }

        [HttpGet]
        public string TestMethod3(int arg0,string arg1)
        {
            return "";
        }

Wenn Sie nur die Datei WebApiConfig.cs ändern können.

 config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/",
                defaults: null
            );

Das ist es :)

Und Ergebnis: Geben Sie hier die Bildbeschreibung ein

Cemre Onur Baş
quelle
0

Haben Sie versucht wie:

[HttpGet("Summary")]
public HttpResponseMessage Summary(MyVm vm)
{
    return null;
}

[HttpGet("FullDetails")]
public HttpResponseMessage FullDetails()
{
    return null;
}
Deepak Shaw
quelle
1
Dies wird in Nicht-.NET Core-Projekten nicht kompiliert, da das HttpGetAttribut keinen Konstruktor hat, der ein Zeichenfolgenargument akzeptiert.
Hoppeduppeanut