Beberapa tindakan ditemukan yang cocok dengan permintaan di Web Api

243

Saya terus mendapatkan kesalahan ini ketika saya mencoba memiliki 2 metode "Dapatkan"

Beberapa tindakan ditemukan yang sesuai dengan permintaan: webapi

Saya telah melihat-lihat pertanyaan serupa lainnya tentang ini di stack tetapi saya tidak mengerti.

Saya memiliki 2 nama berbeda dan menggunakan atribut "HttpGet"

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

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

Jawaban:

485

Peta rute Anda mungkin kira-kira seperti ini:

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

Tetapi untuk memiliki beberapa tindakan dengan metode http yang sama, Anda perlu memberi webapi informasi lebih banyak melalui rute seperti:

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

Perhatikan bahwa routeTemplate sekarang termasuk tindakan. Banyak info lebih lanjut di sini: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

Memperbarui:

Baiklah, sekarang saya pikir saya mengerti apa yang Anda cari di sini adalah satu lagi mengambil ini:

Mungkin Anda tidak memerlukan parameter url tindakan dan harus menjelaskan konten yang Anda cari dengan cara lain. Karena Anda mengatakan bahwa metode mengembalikan data dari entitas yang sama maka biarkan saja parameter yang menjelaskan untuk Anda.

Misalnya, dua metode Anda dapat diubah menjadi:

public HttpResponseMessage Get()
{
    return null;
}

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

Jenis data apa yang Anda berikan pada objek MyVm? Jika Anda hanya bisa melewati variabel melalui URI, saya akan menyarankan pergi rute itu. Kalau tidak, Anda harus mengirim objek di badan permintaan dan itu tidak terlalu HTTP Anda ketika melakukan GET (berfungsi meskipun, cukup gunakan [FromBody] infront dari MyVm).

Semoga ini menggambarkan bahwa Anda dapat memiliki beberapa metode GET dalam satu kontroler tanpa menggunakan nama tindakan atau bahkan atribut [HttpGet].

Jed
sumber
Apakah ada keuntungan melakukan satu atau lain cara? Jika saya melakukan sekunder, apakah saya hanya harus meletakkan tindakan Http pada setiap metode? Apakah itu undian besar?
chobo2
3
Apakah salah satu memiliki keunggulan dibandingkan yang lain benar-benar tergantung pada proyek Anda. Jika Anda sedang membangun api yang TETAP, maka Anda akan ingin menggunakan konvensi HTTP (GET, POST, PUT, DELETE ...). Dalam hal ini blok pertama dari kode routing adalah cara untuk pergi tetapi Anda akan menginginkan pengontrol yang berbeda untuk setiap entitas yang Anda paparkan melalui api. Berdasarkan nama metode Anda, saya rasa ini bukan masalahnya, jadi gunakan perutean yang lebih deskriptif. Saat rute Anda menyertakan tindakan, Anda ingin secara eksplisit menempatkan atribut http pada setiap metode.
Jed
1
@ chobo2 Mengapa tidak hanya menggunakan metode yang diberi nama sesuai dalam controller? GetSummary (MyVm wm) dan GetDetails ()
Jed
1
Terima kasih atas jawaban Anda, hanya membantu saya mengetahui mengapa resolusi rute tidak berfungsi meskipun kedua tindakan saya memiliki nama yang berbeda. Saya benar-benar bingung mengapa bukan hanya perilaku default (yaitu mengapa templat rute default di webapiconfig.cs tidak disertakan "{action}")!
Tejas Sharma
1
@bruno jika menggunakan area Anda juga dapat menambahkan 'admin' API spesifik seperti ini di AdminAreaRegistration stackoverflow.com/a/9849011/16940
Simon_Weaver
67

Pembaruan sebagai Web API 2.

Dengan konfigurasi API ini di file WebApiConfig.cs Anda:

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

Anda dapat merutekan kontroler kami seperti ini:

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

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

Di mana ControllerName adalah nama controller Anda (tanpa "controller"). Ini akan memungkinkan Anda untuk mendapatkan setiap tindakan dengan rute yang dijelaskan di atas.

Untuk bacaan lebih lanjut: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

Marc Stevenson
sumber
Saya sangat menyukai solusi ini. Rute default saya masih sama dan saya memiliki rute "pengecualian" untuk pengecualian
Leandro De Mello Fagundes
Anda juga dapat memetakan parameter ke dalam url EX: [Rute ("api / ControllerName / Summary / {vm}")]
nulltron
15

Di Web API (secara default) metode dipilih berdasarkan kombinasi metode HTTP dan nilai rute .

MyVmterlihat seperti objek yang kompleks, dibaca oleh formatter dari badan sehingga Anda memiliki dua metode yang identik dalam hal data rute (karena tidak satu pun dari mereka memiliki parameter dari rute) - yang membuatnya mustahil bagi operator ( IHttpActionSelector) untuk mencocokkan yang sesuai .

Anda perlu membedakan mereka dengan parameter querystring atau rute untuk menyelesaikan ambiguitas.

Filipus W
sumber
14

Setelah banyak mencari di web dan berusaha mencari bentuk yang paling cocok untuk perutean peta jika sudah menemukan yang berikut ini

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

Pemetaan ini berlaku untuk pemetaan nama tindakan dan konvensi http dasar (GET, POST, PUT, DELETE)

Moatasem bakri
sumber
9
Bagi saya ini berhasil, tetapi hanya setelah mengubah urutan rute dalam konfigurasi rute sehingga orang yang beraksi muncul lebih dulu
Fredrik Stolpe
tepatnya pesanan itu penting di sini
AT
5

Tanpa menggunakan tindakan, pilihannya adalah:

  1. pindahkan salah satu metode ke pengontrol yang berbeda, sehingga tidak berbenturan.

  2. gunakan hanya satu metode yang mengambil param, dan jika itu nol panggil metode lain dari kode Anda.

Joanna Derks
sumber
Ini mungkin solusi, tapi bukan yang optimal, toh +1 dari pihak saya :)
satish kumar V
4

Solusi ini bekerja untuk saya.

Harap tempatkan Route2 terlebih dahulu di WebApiConfig. Juga Tambahkan HttpGet dan HttpPost sebelum setiap metode dan sertakan nama pengontrol dan nama metode di url.

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

Pengendali =>

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
sumber
4

Ini adalah jawaban untuk semua orang yang tahu semuanya benar dan telah memeriksa 50 kali .....

Pastikan Anda tidak berulang kali melihatnya RouteConfig.cs.

File yang ingin Anda edit diberi nama WebApiConfig.cs

Juga, seharusnya terlihat persis seperti ini:

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

Saya bisa menyelamatkan diri sekitar 3 jam.

CarComp
sumber
1
Terima kasih, Anda menyelamatkan saya sekitar 3 jam
geedubb
3

Saya menemukan bahwa ketika saya memiliki dua metode Get, satu parameterless dan satu dengan tipe kompleks sebagai parameter saya mendapatkan kesalahan yang sama. Saya memecahkan ini dengan menambahkan parameter dummy dari tipe int, bernama Id, sebagai parameter pertama saya, diikuti oleh parameter tipe kompleks saya. Saya kemudian menambahkan parameter tipe kompleks ke templat rute. Berikut ini bekerja untuk saya.

Pertama dapatkan:

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

Kedua dapatkan:

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
sumber
3

Ini dimungkinkan karena menggunakan pengontrol MVC alih-alih pengontrol API Web. Periksa namespace di kontroler Web API itu harus sebagai berikut

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

Jika namespace adalah sebagai berikut maka itu memberikan kesalahan di atas dalam pemanggilan metode pengontrol api web

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

Periksa Anda memiliki dua metode yang memiliki nama berbeda dan parameter yang sama.

Jika demikian harap hapus salah satu metode dan coba.

Ramesh
sumber
2

Saya menemukan masalah ini ketika mencoba menambah pengontrol WebAPI saya dengan tindakan ekstra.

Anggaplah Anda akan memilikinya

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

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

Sekarang ada dua metode yang memenuhi permintaan untuk / api / controller yang memicu masalah yang dijelaskan oleh TS.

Saya tidak ingin menambahkan parameter "dummy" ke tindakan tambahan saya, jadi saya melihat ke tindakan default dan menghasilkan:

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

untuk metode pertama dalam kombinasi dengan pengikatan rute "ganda":

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

Perhatikan bahwa meskipun tidak ada parameter "aksi" di templat rute pertama rupanya Anda masih dapat mengonfigurasi tindakan default yang memungkinkan kami untuk memisahkan perutean panggilan WebAPI "normal" dan panggilan ke tindakan ekstra.

Bjørn van Dommelen
sumber
2

Dalam Kasus saya Semuanya benar

1) Konfigurasi Web dikonfigurasi dengan benar 2) Rute awalan dan atribut Rute sudah benar

Masih saya mendapatkan kesalahan. Dalam kasus "Rute" atribut saya (dengan menekan F12) menunjuk ke System.Web.MVc tetapi tidak System.Web.Http yang menyebabkan masalah.

Hemanth Vatti
sumber
Jawaban ini sangat membantu saya!
tvb108108
1

Anda dapat menambahkan [Route("api/[controller]/[action]")]ke kelas controller Anda.

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

Saya tahu ini adalah pertanyaan lama, tetapi kadang-kadang, ketika Anda menggunakan sumber daya layanan seperti dari AngularJS untuk terhubung ke WebAPI, pastikan Anda menggunakan rute yang benar, jika tidak maka kesalahan ini terjadi.

Suresh Kaushik
sumber
0

Pastikan Anda TIDAK menghias metode Kontroler Anda untuk aksi GET | PUT | POST | DELETE default dengan atribut [HttpPost / Put / Get / Delete]. Saya telah menambahkan attibute ini ke action vanilla Post controller saya dan menyebabkan 404.

Semoga ini bisa membantu seseorang karena bisa sangat membuat frustrasi dan membuat kemajuan terhenti.

Silahkan masuk
sumber
0

Misalnya => TestController

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

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

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

Jika Anda hanya dapat mengubah file WebApiConfig.cs.

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

Itu dia :)

Dan hasil: masukkan deskripsi gambar di sini

Cemre Onur Baş
sumber
0

Sudahkah Anda mencoba seperti:

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

[HttpGet("FullDetails")]
public HttpResponseMessage FullDetails()
{
    return null;
}
Deepak Shaw
sumber
1
Ini tidak akan dikompilasi dalam proyek Core non-.NET, karena HttpGetatribut tidak memiliki konstruktor yang menerima argumen string.
Hoppeduppeanut