Web API denetleyicisinde birden çok HttpPost yöntemi


126

MVC4 Web API projesini kullanmaya başlıyorum, birden fazla HttpPostyöntemle kontrolcüm var . Denetleyici aşağıdaki gibi görünür:

kontrolör

public class VTRoutingController : ApiController
{
    [HttpPost]
    public MyResult Route(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }

    [HttpPost]
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }
}

Burada MyRequestTemplate, istek aracılığıyla gelen Json'ı işlemekten sorumlu şablon sınıfını temsil eder.

Hata:

Fiddler'ı kullanarak istekte bulunduğumda http://localhost:52370/api/VTRouting/TSPRouteveya http://localhost:52370/api/VTRouting/Route bir hata aldığımda:

İstekle eşleşen birden çok işlem bulundu

Yukarıdaki yöntemlerden birini kaldırırsam iyi çalışıyor.

Global.asax

Varsayılan yönlendirme tablosunu içinde değiştirmeyi denedim global.asax, ancak hala hatayı alıyorum, global.asax'ta yolları tanımlamada sorun yaşadığımı düşünüyorum. İşte global.asax'ta yaptığım şey.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapHttpRoute(
        name: "MyTSPRoute",
        routeTemplate: "api/VTRouting/TSPRoute",
        defaults: new { }
    );

    routes.MapHttpRoute(
        name: "MyRoute",
        routeTemplate: "api/VTRouting/Route",
        defaults: new { action="Route" }
    );
}

POST kullanarak Fiddler'da istek yapıyorum, MyRequestTemplate için RequestBody'de json'u geçiyorum.

Yanıtlar:


143

Tek bir denetleyicide birden fazla eyleminiz olabilir.

Bunun için aşağıdaki iki şeyi yapmanız gerekir.

  • Önce eylemleri şu ActionNameniteliklerle süsleyin:

     [ActionName("route")]
     public class VTRoutingController : ApiController
     {
       [ActionName("route")]
       public MyResult PostRoute(MyRequestTemplate routingRequestTemplate)
       {
         return null;
       }
    
      [ActionName("tspRoute")]
      public MyResult PostTSPRoute(MyRequestTemplate routingRequestTemplate)
      {
         return null;
      }
    }
  • İkinci olarak aşağıdaki rotaları WebApiConfigdosyada tanımlayın .

    // Controller Only
    // To handle routes like `/api/VTRouting`
    config.Routes.MapHttpRoute(
        name: "ControllerOnly",
        routeTemplate: "api/{controller}"               
    );
    
    
    // Controller with ID
    // To handle routes like `/api/VTRouting/1`
    config.Routes.MapHttpRoute(
        name: "ControllerAndId",
        routeTemplate: "api/{controller}/{id}",
        defaults: null,
        constraints: new { id = @"^\d+$" } // Only integers 
    );
    
    // Controllers with Actions
    // To handle routes like `/api/VTRouting/route`
    config.Routes.MapHttpRoute(
        name: "ControllerAndAction",
        routeTemplate: "api/{controller}/{action}"
    );

Kimliğin türüne herhangi bir kısıtlama koymak istemezsem ne olur? Anlamı: string kimliklerini nasıl kabul edebilirim?
frapontillo

5
@frapontillo: Id, rota adından ayrılması için bir tamlayıcı olmalıdır, aksi takdirde yönlendirme uzmanı onu bir kimlik yerine bir eylem adı olarak ele alır. Dizge olarak id'ye ihtiyacınız varsa, bir eylem oluşturabilirsiniz.
Asif Mushtaq

Bunun yerine Öznitelik Yönlendirme kullanırım. WebApiConfig konsolunda bu şekilde birden çok yol kullanmanız gerekmez. Şu bağlantıya göz atın: docs.microsoft.com/en-us/aspnet/web-api/overview/…
Zengin

Bu şekilde eklersem, bana bir hata veriyor ------------ ad alanı ImageDownloadApplication.Controllers {public class FrontModel {public string skus {get; Ayarlamak; }} [ActionName ("ProductController")] genel sınıf ProductController: ApiController {// GET: api / NewCotroller public IEnumerable <string> Get () {return new string [] {"value1", "value2"}; }
Umashankar

42

Sorununuza çok daha iyi bir çözüm Route, yöntem üzerinde ek açıklama ile rotayı belirtmenize izin veren kullanmak olacaktır :

[RoutePrefix("api/VTRouting")]
public class VTRoutingController : ApiController
{
    [HttpPost]
    [Route("Route")]
    public MyResult Route(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }

    [HttpPost]
    [Route("TSPRoute")]
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }
}

Rota hangi Ad Alanı içindedir? MVC4 kullanıyorum ve Rota tanınmıyor.
eaglei22


Evet, gitmesi gereken yol bu. Teşekkürler.
newman

1
Bazı nedenlerden dolayı bunu çalıştıramıyorum. bu tam olarak zaten yaptığım şeydi.
oligofren

2
URL, aramaktan daha nasıl görünürdü Routeve TSPRoute?
Si8

27

kullanın:

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

artık RESTful bir yaklaşım değil, ancak artık eylemlerinizi adıyla çağırabilirsiniz (Web API'sinin fiile göre sizin için otomatik olarak bir tane belirlemesine izin vermek yerine) şu şekilde:

[POST] /api/VTRouting/TSPRoute

[POST] /api/VTRouting/Route

Popüler inanışın aksine, bu yaklaşımda yanlış bir şey yoktur ve Web API'yi kötüye kullanmaz. Yine de Web API'nin tüm harika özelliklerinden (işleyicileri temsil etme, içerik uzlaşması, ortam biçimlendiricileri vb.) Yararlanabilirsiniz - sadece RESTful yaklaşımından vazgeçersiniz.


1
Cevap için teşekkürler, ama yine de bana aynı hatayı veriyor.
Habib

Bu mümkün değil, o zaman uygulamanızda başka bir şey yanlış yapılandırılmalıdır. Tüm Rota kurulumunu gösterebilir misin? Ayrıca denetleyicilerin eylemlerini tam olarak nasıl adlandırıyorsunuz?
Filip W

Rota kurulumunun tamamı global.asax'ta, sorumda o bölümü gönderdim, İstekte bulunmak için Fiddler-> Compose-> kullanıyorum ve işlem olarak Gönder'i seçiyorum
Habib

diğer tüm rota tanımlarını kaldırmayı deneyin ve sadece gönderdiğim yolu bırakın. Ardından, bir denetleyicide bulunan her iki POST eylemini de kolayca çağırabilirsiniz (eski MVC yaklaşımıyla aynı)
Filip W

1
Filip, mvc4 veya Visual studio 2012 RC ile .Net framework 4.5 kullanıyorum, Projenizi oluşturmak için hangi şablonu kullanıyorsunuz, sizinki mükemmel çalışıyor
Habib

13

Bir web api uç noktası (denetleyici), get / post / put / delete fiillerini kabul eden tek bir kaynaktır. Öyle olmayan normal MVC kontrol ünitesi.

Mutlaka, gönderdiğiniz parametreleri kabul eden /api/VTRoutingyalnızca bir HttpPost yöntemi olabilir. [Http] öğeleriyle dekorasyon yaptığınız sürece işlev adı önemli değildir . Yine de hiç denemedim.

Düzenleme: Bu çalışmıyor. Çözümlemede, türe model bağlamaya çalışmak yerine, parametre sayısına göre gidiyor gibi görünüyor.

Farklı parametreleri kabul etmek için fonksiyonları aşırı yükleyebilirsiniz. Bunu yaptığınız gibi bildirirseniz, ancak yöntemlere farklı (uyumsuz) parametreler kullanırsanız, iyi olacağınıza oldukça eminim. Parametreler aynıysa, şansınız kalmaz, çünkü model bağlama hangisini kastettiğinizi bilemez.

[HttpPost]
public MyResult Route(MyRequestTemplate routingRequestTemplate) {...}

[HttpPost]
public MyResult TSPRoute(MyOtherTemplate routingRequestTemplate) {...}

Bu bölüm çalışıyor

Yeni bir tane oluşturduğunuzda verdikleri varsayılan şablon bunu oldukça açık hale getiriyor ve bu kurala bağlı kalmanız gerektiğini söyleyebilirim:

public class ValuesController : ApiController
{
    // GET is overloaded here.  one method takes a param, the other not.
    // GET api/values  
    public IEnumerable<string> Get() { .. return new string[] ... }
    // GET api/values/5
    public string Get(int id) { return "hi there"; }

    // POST api/values (OVERLOADED)
    public void Post(string value) { ... }
    public void Post(string value, string anotherValue) { ... }
    // PUT api/values/5
    public void Put(int id, string value) {}
    // DELETE api/values/5
    public void Delete(int id) {}
}

Ajax kullanımı için birçok şey yapan bir sınıf yapmak istiyorsanız, standart bir denetleyici / eylem modeli kullanmamak için büyük bir neden yoktur. Tek gerçek fark, yöntem imzalarınızın o kadar güzel olmaması ve Json( returnValue)iade etmeden önce her şeyi sarmalamanız gerekir.

Düzenle:

Basit türleri kullanırken standart şablonu (dahil etmek için düzenlenmiş) kullanırken aşırı yükleme gayet iyi çalışır. Farklı imzalara sahip 2 özel nesne ile diğer yolu da test ettim. Asla işe yaramadı.

  • Karmaşık nesnelerle bağlanmak "derin" görünmüyor, bu nedenle
  • Sorgu dizesine fazladan bir parametre ileterek bunu aşabilirsiniz.
  • Mevcut seçenekler hakkında verebileceğimden daha iyi bir yazı

Bu, bu durumda benim için çalıştı, sizi nereye götürdüğüne bakın. Yalnızca test için istisna.

public class NerdyController : ApiController
{
    public void Post(string type, Obj o) { 
        throw new Exception("Type=" + type + ", o.Name=" + o.Name ); 
    }
}

public class Obj {
    public string Name { get; set; }
    public string Age { get; set; }
}

Ve konsoldan şöyle adlandırılır:

$.post("/api/Nerdy?type=white", { 'Name':'Slim', 'Age':'21' } )

Parametre türlerini değiştirmeyi denedim, ancak denetleyicide yalnızca tek bir Post yöntemine izin veriyor gibi görünüyor. Cevabınız için teşekkürler
Habib

Aşırı yükleyebileceğiniz için, onu bulmak için model bağlamayı deneyeceğini varsaydım. Yine de farklı parametrelerle çalışır. O bu olsa yapmak zor yeniden yazma olmayabilir, ama sadece sökme çirkin bakarak sıkışıp kaldım bu yüzden, henüz kaynak kodunu yayınladı değil
Andrew Backer

2
Çalışmama nedenini ve web api'nin arkasındaki felsefeyi açıklamak için +1.
MEMark

Bozulmayı takdir edin ... Denetleyici başına tek bir POST / PUT / GET olması gerektiğini varsaydım ama emin değildim ... bu yüzden bakmamın nedeni buydu. Denetleyici başına birden çok benzer eylemin norm olduğu web uygulamaları için MVC ile geliştirmeye başladığımdan beri ... bu neredeyse bir israf gibi görünüyor, bu yüzden bir geliştiricinin neden isteyeceğini anlayabiliyorum. Çok fazla denetleyici diye bir şey var mı?
Anthony Griggs

6

Aynı Web API Denetleyicisine Birden Çok Alma ve Gönderme yöntemi eklemek mümkündür. Burada varsayılan Rota Soruna Neden Oluyor. Web API, Yukarıdan Aşağıya Rotayı ve Dolayısıyla tüm İstekler için Varsayılan Rota Eşleşmelerini kontrol eder. Varsayılan yol olarak, bir denetleyicide yalnızca bir Alma ve Gönderme Yöntemi mümkündür. Aşağıdaki kodu en üste yerleştirin veya Yorum Gönderme / Varsayılan Rotayı Silme

    config.Routes.MapHttpRoute("API Default", 
                               "api/{controller}/{action}/{id}",
                               new { id = RouteParameter.Optional });

1

Rota Önekini [RoutePrefix ("api / Profiles")] kontrolör seviyesinde koyun ve [Route ("LikeProfile")] eylem metoduna bir yol koyun. Global.asax dosyasında hiçbir şeyi değiştirmenize gerek yok

namespace KhandalVipra.Controllers
{
    [RoutePrefix("api/Profiles")]
    public class ProfilesController : ApiController
    {
        // POST: api/Profiles/LikeProfile
        [Authorize]
        [HttpPost]
        [Route("LikeProfile")]
        [ResponseType(typeof(List<Like>))]
        public async Task<IHttpActionResult> LikeProfile()
        {
        }
    }
}

0

Sanırım soru zaten cevaplandı. Aynı imzalı mehtodlara ancak farklı adlara sahip bir webApi denetleyicisi de arıyordum. Hesap Makinesi'ni WebApi olarak uygulamaya çalışıyordum. Hesap makinesinin aynı imzaya sahip ancak farklı adlara sahip 4 yöntemi vardır.

public class CalculatorController : ApiController
{
    [HttpGet]
    [ActionName("Add")]
    public string Add(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Add = {0}", num1 + num2);
    }

    [HttpGet]
    [ActionName("Sub")]
    public string Sub(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Subtract result = {0}", num1 - num2);
    }

    [HttpGet]
    [ActionName("Mul")]
    public string Mul(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Multiplication result = {0}", num1 * num2);
    }

    [HttpGet]
    [ActionName("Div")]
    public string Div(int num1 = 1, int num2 = 1, int timeDelay = 1)
    {
        Thread.Sleep(1000 * timeDelay);
        return string.Format("Division result = {0}", num1 / num2);
    }
}

ve WebApiConfig dosyasında zaten sahip olduğunuz

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

Sadece IIS'de kimlik doğrulama / yetkilendirmeyi ayarlayın ve bitirdiniz!

Bu yardımcı olur umarım!


0

Bu yaklaşımı kullanabilirsiniz:

public class VTRoutingController : ApiController
{
    [HttpPost("Route")]
    public MyResult Route(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }

    [HttpPost("TSPRoute")]
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }
}

-1
public class Journal : ApiController
{
    public MyResult Get(journal id)
    {
        return null;
    }
}

public class Journal : ApiController
{

    public MyResult Get(journal id, publication id)
    {
        return null;
    }
}

Get / post yönteminin aşırı yüklenmesinin restfull api kavramını ihlal edip etmediğinden emin değilim, ancak işe yarıyor. Bu konuda aydınlatabilecek biri olsaydı. Ya bir uri'm varsa

uri:/api/journal/journalid
uri:/api/journal/journalid/publicationid

Bu yüzden dergimde gördüğünüz gibi bir tür aggregateroot, ancak yalnızca yayın için başka bir denetleyici tanımlayabilir ve url'mde yayın kimlik numarasını iletebilirim ancak bu çok daha anlamlı. çünkü benim yayınım dergi olmadan var olmazdı.


-1

URL'ye az önce "action = action_name" ekledim ve bu şekilde yönlendirme motoru istediğim eylemi biliyor. Eylemlere ActionName Özniteliğini de ekledim ancak gerekli olduğundan emin değilim.


-1

Bu konuda gördüğüm en iyi ve en basit açıklama - http://www.binaryintellect.net/articles/9db02aa1-c193-421e-94d0-926e440ed297.aspx

  • Düzenlendi -

Onu sadece Route ile çalıştırdım ve RoutePrefix'e ihtiyacım yoktu.

Örneğin, kontrolörde

[HttpPost]
[Route("[action]")]
public IActionResult PostCustomer
([FromBody]CustomerOrder obj)
{
}

ve

[HttpPost]
[Route("[action]")]
public IActionResult PostCustomerAndOrder
([FromBody]CustomerOrder obj)
{
}

Daha sonra, işlev adı jquery'de ya -

options.url = "/api/customer/PostCustomer";

veya

options.url = "/api/customer/PostCustomerAndOrder";
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.