वेब एपीआई नियंत्रक में एकाधिक HttpPost विधि


126

मैं MVC4 वेब एपीआई परियोजना का उपयोग करना शुरू कर रहा हूं, मेरे पास कई HttpPostविधियों के साथ नियंत्रक है । नियंत्रक निम्नलिखित की तरह दिखता है:

नियंत्रक

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

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

यहाँ MyRequestTemplateअनुरोध के माध्यम से आने वाले Json को संभालने के लिए जिम्मेदार टेम्पलेट वर्ग का प्रतिनिधित्व करता है।

त्रुटि:

जब मैं के लिए फ़िडलर का उपयोग कर एक अनुरोध करना http://localhost:52370/api/VTRouting/TSPRouteया http://localhost:52370/api/VTRouting/Route मैं कोई त्रुटि मिलती है:

कई कार्य पाए गए जो अनुरोध से मेल खाते हैं

यदि मैं उपरोक्त विधि में से एक को हटाता हूं तो यह ठीक काम करता है।

Global.asax

मैंने डिफ़ॉल्ट रूटिंग तालिका को संशोधित करने का प्रयास किया है global.asax, लेकिन मुझे अभी भी त्रुटि मिल रही है, मुझे लगता है कि मुझे Global.asax में मार्गों को परिभाषित करने में समस्या है। यहां मैं वही कर रहा हूं जो मैं वैश्विकता में कर रहा हूं।

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 का उपयोग करके Fiddler में अनुरोध कर रहा हूं, MyRequestTemplate के लिए RequestBody में json गुजर रहा है।

जवाबों:


143

आप एक ही नियंत्रक में कई कार्य कर सकते हैं।

उसके लिए आपको निम्नलिखित दो काम करने होंगे।

  • पहले ActionNameविशेषता के साथ कार्यों को सजाने की तरह

     [ActionName("route")]
     public class VTRoutingController : ApiController
     {
       [ActionName("route")]
       public MyResult PostRoute(MyRequestTemplate routingRequestTemplate)
       {
         return null;
       }
    
      [ActionName("tspRoute")]
      public MyResult PostTSPRoute(MyRequestTemplate routingRequestTemplate)
      {
         return null;
      }
    }
  • दूसरा WebApiConfigफ़ाइल में निम्नलिखित मार्गों को परिभाषित करता है ।

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

अगर मैं आईडी के प्रकार पर कोई प्रतिबंध नहीं लगाना चाहता तो क्या होगा? अर्थ: मैं स्ट्रिंग आईडी भी कैसे स्वीकार कर सकता हूं?
frapontillo

5
@frapontillo: आईडी एक पूर्णांक होनी चाहिए, ताकि यह मार्ग के नाम से अलग हो जाए अन्यथा मार्ग एनगाइन इसे एक कार्रवाई नाम के रूप में माना जाएगा, फिर एक आईडी। अगर आपको आईडी को स्ट्रिंग की आवश्यकता है तो आप एक एक्शन बना सकते हैं।
आसिफ मुश्ताक

मैं इसके बजाय अट्रैक्शन रूटिंग का उपयोग करूंगा। आपको WebApiConfig में कई मार्गों का उपयोग नहीं करना पड़ेगा। इस लिंक को देखें: docs.microsoft.com/en-us/aspnet/web-api/overview/…
रिच

अगर मैं इसे इस तरह जोड़ता हूं तो यह मुझे एक त्रुटि देता है ------------ नामस्थान ImageDownloadApplication.Controllers {सार्वजनिक वर्ग FrontModel {सार्वजनिक स्ट्रिंग skus {प्राप्त करें; सेट; }} [ActionName ("ProductController")] पब्लिक क्लास ProductController: ApiController {// GET: api / NewCotroller public IEnumerable <string> Get () {रिटर्न न्यू स्ट्रिंग [} "value1", "value2"}; }
उमाशंकर

42

आपकी समस्या का एक बेहतर समाधान यह होगा Routeकि आप एनोटेशन द्वारा विधि पर मार्ग निर्दिष्ट करें:

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

क्या नामस्थान मार्ग में है? मैं MVC4 का उपयोग कर रहा हूं और रूट को मान्यता नहीं मिली है।
ईगलिंग 22

2 निम्नलिखित स्रोतों को देखें asp.net/web-api/overview/web-ap-rout-and-actions/… asp.net/web-api/overview/web-ap-rout-and-actions/…
Wisienkas

हां, यह तरीका है कि इसे जाना चाहिए। धन्यवाद।
न्यूमन

1
किसी कारण से मुझे यह काम नहीं मिल रहा है। यह वही है जो मैं पहले से कर रहा था।
ऑलिगॉफ्रेन

2
कॉल करने के बजाय url कैसा दिखेगा Routeऔर TSPRoute?
Si8

27

उपयोग:

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

यह अब एक RESTful दृष्टिकोण नहीं है, लेकिन आप अब अपने कार्यों को नाम से कह सकते हैं (बजाय इसके कि वेब एपीआई स्वचालित रूप से क्रिया के आधार पर आपके लिए एक निर्धारित करें):

[POST] /api/VTRouting/TSPRoute

[POST] /api/VTRouting/Route

आम धारणा के विपरीत, इस दृष्टिकोण में कुछ भी गलत नहीं है, और यह वेब एपीआई का दुरुपयोग नहीं कर रहा है। आप अभी भी वेब एपीआई (प्रतिनिधि संचालकों, सामग्री वार्ता, मध्यस्थता-पूर्व और इतने पर प्रतिनिधि) की सभी भयानक विशेषताओं का लाभ उठा सकते हैं - आप केवल Restful दृष्टिकोण को खोद सकते हैं।


1
उत्तर के लिए धन्यवाद, लेकिन यह अभी भी मुझे वही त्रुटि दे रहा है।
हबीब

यह संभव नहीं है, तो आपके ऐप में कुछ और गलत होना चाहिए। क्या आप पूरा रूट सेटअप दिखा सकते हैं? यह भी कि वास्तव में आप नियंत्रकों को कैसे बुला रहे हैं?
फिलिप

संपूर्ण रूट सेटअप Global.asax में है, मेरे पास मेरे प्रश्न में वह हिस्सा है, अनुरोध करने के लिए, मैं फ़िडलर का उपयोग कर रहा हूं-> लिखें-> और ऑपरेशन के रूप में पोस्ट का चयन कर रहा हूं
हबीब

अन्य सभी मार्गों की परिभाषा को हटाने का प्रयास करें और केवल एक जिसे मैंने पोस्ट किया है उसे छोड़ दें। तब आप आसानी से एक कंट्रोलर (पुराने MVC दृष्टिकोण के समान) के भीतर स्थित दोनों POST कार्यों को कॉल कर सकते हैं
फिलिप डब्ल्यू

1
Filip, मैं .Net फ्रेमवर्क 4.5 का उपयोग कर रहा हूं, mvc4 या विज़ुअल स्टूडियो 2012 RC के साथ, आप अपनी परियोजना बनाने के लिए किस टेम्पलेट का उपयोग कर रहे हैं, आपका 'पूरी तरह से काम कर रहा है
हबीब

13

एक वेब एपि समापन बिंदु (नियंत्रक) एक एकल संसाधन है जो क्रियाओं को प्राप्त / पोस्ट / पुट / डिलीट करता है। यह है नहीं एक सामान्य MVC नियंत्रक।

आवश्यक रूप से, /api/VTRoutingकेवल एक ही HttpPost विधि हो सकती है जो आपके द्वारा भेजे जा रहे मापदंडों को स्वीकार करती है। फ़ंक्शन का नाम कोई फर्क नहीं पड़ता , जब तक आप [http] सामान के साथ सजा रहे हैं। मैंने कभी कोशिश नहीं की, हालांकि।

संपादित करें: यह काम नहीं करता है। हल करने में, यह मापदंडों की संख्या से जाना लगता है, प्रकार के लिए मॉडल-बाइंड करने की कोशिश नहीं कर रहा है।

आप विभिन्न मापदंडों को स्वीकार करने के लिए कार्यों को ओवरलोड कर सकते हैं। मुझे पूरा यकीन है कि आप ठीक होंगे यदि आपने इसे वैसे ही घोषित कर दिया है, लेकिन तरीकों के लिए अलग (असंगत) मापदंडों का उपयोग किया है। यदि समान हैं, तो आप भाग्य से बाहर हैं क्योंकि मॉडल बाइंडिंग को पता नहीं चलेगा कि आपका कौन सा मतलब है।

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

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

यह हिस्सा काम करता है

जब आप एक नया निर्माण करते हैं, तो डिफ़ॉल्ट टेम्पलेट वे इसे बहुत स्पष्ट करते हैं, और मैं कहूंगा कि आपको इस सम्मेलन के साथ रहना चाहिए:

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

यदि आप एक वर्ग बनाना चाहते हैं जो कई काम करता है, तो अजाक्स के उपयोग के लिए, मानक नियंत्रक / कार्रवाई पैटर्न का उपयोग नहीं करने का कोई बड़ा कारण नहीं है। एकमात्र वास्तविक अंतर यह है कि आपके विधि हस्ताक्षर उतने सुंदर नहीं हैं, और आपको Json( returnValue)उन्हें वापस करने से पहले चीजों को लपेटना होगा।

संपादित करें:

सरल प्रकारों का उपयोग करते समय मानक टेम्पलेट (शामिल करने के लिए संपादित) का उपयोग करते समय ओवरलोडिंग ठीक काम करती है। मैंने अलग-अलग हस्ताक्षर के साथ 2 कस्टम ऑब्जेक्ट्स के साथ दूसरे तरीके से भी परीक्षण किया है। काम करने के लिए कभी नहीं मिल सका।

इस मामले में यह मेरे लिए काम करता है, देखें कि यह आपको कहां मिलता है। केवल परीक्षण के लिए अपवाद।

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

और इस फॉर्म को कंसोल कहते हैं:

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

मैंने पैरामीटर प्रकार बदलने की कोशिश की है, लेकिन ऐसा लगता है कि यह केवल नियंत्रक में एक एकल पोस्ट विधि की अनुमति देता है। आपके उत्तर के लिए धन्यवाद
हबीब

मैंने मान लिया था कि इसे खोजने के लिए मॉडल बाइंडिंग की कोशिश करेगा, क्योंकि आप ओवरलोड कर सकते हैं। यह विभिन्न # परम के साथ काम करता है, हालांकि। यह ऐसा करने के लिए इसे फिर से लिखना इतना कठिन नहीं हो सकता है, लेकिन उन्होंने अभी तक स्रोत कोड जारी नहीं किया है, इसलिए मैं सिर्फ बदसूरत डिसएफ़ॉर्म को देख रहा हूं
एंड्रयू बैकर

2
+1 वास्तव में यह काम नहीं करने का कारण बताते हुए, और वेब एपीआई के पीछे दर्शन।
मेमोरियल

ब्रेक डाउन की सराहना करें ... मैंने मान लिया था कि यह एक ही POST / PUT / GET प्रति नियंत्रक होना चाहिए था, लेकिन मुझे यकीन नहीं था ... इस कारण मैंने इसे देखा। जब से मैंने वेब ऐप के लिए एमवीसी के साथ विकसित करना शुरू किया है, जहां प्रति नियंत्रक की तरह कई कार्य मानक हैं ... यह लगभग एक बेकार लगता है इसलिए मैं समझ सकता हूं कि एक डेवलपर क्यों चाहेगा। क्या बहुत अधिक नियंत्रकों जैसी कोई चीज है?
एंथनी ग्रिग्ज

6

एक ही वेब एपीआई नियंत्रक में कई गेट और पोस्ट विधियों को जोड़ना संभव है। यहाँ डिफ़ॉल्ट रूट समस्या का कारण है। वेब एपीआई ऊपर से नीचे तक मिलान मार्ग के लिए जाँच करता है और इसलिए आपके डिफ़ॉल्ट मार्ग सभी अनुरोधों के लिए मेल खाता है। डिफ़ॉल्ट मार्ग के अनुसार एक नियंत्रक में केवल एक गेट और पोस्ट विधि संभव है। या तो निम्न कोड को शीर्ष पर रखें या डिफॉल्ट रूट को हटाएं / हटाएं

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

1

रूट प्रीफ़िक्स [रूटप्रिफ़िक्स ("एपि / प्रोफाइल")] को नियंत्रक स्तर पर रखें और एक्शन विधि [रूट ("लाइकप्रोफाइल")] पर एक रूट डालें। Global.asax फ़ाइल में कुछ भी बदलने की आवश्यकता नहीं है

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

मुझे लगता है कि इस सवाल का जवाब पहले ही मिल चुका है। मैं एक वेबएपीआई नियंत्रक की भी तलाश कर रहा था, जिसमें एक ही हस्ताक्षरित मेहता, लेकिन अलग-अलग नाम हों। मैं कैलकुलेटर को वेबएपी के रूप में लागू करने की कोशिश कर रहा था। कैलकुलेटर में एक ही हस्ताक्षर के साथ 4 विधियां हैं लेकिन अलग-अलग नाम हैं।

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

और आपके पास पहले से मौजूद WebApiConfig फ़ाइल में

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

बस IIS पर प्रमाणीकरण / प्राधिकरण सेट करें और आप कर रहे हैं!

उम्मीद है की यह मदद करेगा!


0

आप इस दृष्टिकोण का उपयोग कर सकते हैं:

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

मुझे यकीन नहीं है कि ओवरलोडिंग / पोस्ट विधि से रिस्टफ़ुल एपी की अवधारणा का उल्लंघन होता है, लेकिन यह काम करता है। अगर किसी को भी इस मामले पर ज्ञान हो सकता है। क्या होगा अगर मेरे पास एक उड़ी है

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

इसलिए जैसा कि आपने मेरी पत्रिका को एग्रीगेटर के रूप में देखा है, हालांकि मैं प्रकाशन के लिए एक अन्य नियंत्रक को परिभाषित कर सकता हूं और मेरे यूआरएल में प्रकाशन की आईडी संख्या को पास कर सकता हूं, लेकिन इससे बहुत अधिक समझ में आता है। चूँकि मेरा प्रकाशन बिना पत्रिका के अस्तित्व में नहीं होता।


-1

मैंने सिर्फ "एक्शन = एक्शन_नाम" को यूआरएल में जोड़ा है और इस तरह से रूटिंग इंजन को पता है कि मुझे क्या एक्शन चाहिए। मैंने क्रियाओं में ActionName विशेषता को भी जोड़ा है लेकिन मुझे यकीन नहीं है कि इसकी आवश्यकता है।


-1

इस विषय पर सबसे अच्छी और सरल व्याख्या मैंने देखी - http://www.binaryintellect.net/articles/9db02aa1-c193-421e-94d0-926e440ed297.aspx

  • संपादित -

मुझे यह केवल रूट के साथ काम कर रहा था, और रूटप्रिफ़िक्स की आवश्यकता नहीं थी।

उदाहरण के लिए, नियंत्रक में

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

तथा

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

फिर, फ़ंक्शन का नाम jquery में भी जाता है -

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

या

options.url = "/api/customer/PostCustomerAndOrder";
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.