Вопрос по asp.net-web-api, asp.net-web-api-routing, global-asax, c# – Множественный метод HttpPost в контроллере Web API

120

Я начинаю использовать проект MVC4 Web API, у меня есть контроллер с несколькимиHttpPost методы. Контроллер выглядит следующим образом:

Controller

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

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

Here MyRequestTemplate represents the template class responsible for handling the Json coming through the request.

Error:

Когда я делаю запрос, используя Fiddler дляhttp://localhost:52370/api/VTRouting/TSPRoute или жеhttp://localhost:52370/api/VTRouting/Route  Я получаю ошибку:

Multiple actions were found that match the request

Если я удаляю один из вышеуказанных методов, он работает нормально.

Global.asax

Я попытался изменить таблицу маршрутизации по умолчанию в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" }
    );
}

Я делаю запрос в Fiddler, используя POST, передавая json в RequestBody для MyRequestTemplate.

Ваш Ответ

10   ответов
0

что вопрос уже был дан ответ. Я также искал что-то контроллер webApi, который имеет те же подписанные методы, но разные имена. Я пытался реализовать калькулятор как WebApi. Калькулятор имеет 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, и все готово!

Надеюсь это поможет!

137

Для этого вы должны сделать следующие две вещи.

First decorate actions with ActionName attribute like

 [ActionName("route")]
 public class VTRoutingController : ApiController
 {
   [ActionName("route")]
   public MyResult PostRoute(MyRequestTemplate routingRequestTemplate)
   {
     return null;
   }

  [ActionName("tspRoute")]
  public MyResult PostTSPRoute(MyRequestTemplate routingRequestTemplate)
  {
     return null;
  }
}

Second define the following routes in WebApiConfig file.

// 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}"
);
Если я добавлю вот так, это выдаст мне ошибку ------------ namespace ImageDownloadApplication.Controllers {public class FrontModel {public string skus {get; задавать; }} [ActionName (& quot; ProductController & quot;)] открытый класс ProductController: ApiController {// GET: api / NewCotroller public IEnumerable & lt; string & gt; Get () {вернуть новую строку [] {& quot; значение1 & quot ;, & quot; значение2 & quot; }; }
все, что нам нужно проверить, это не работает
Что если я не хочу устанавливать какие-либо ограничения на тип идентификатора? Значение: как я могу принять строковые идентификаторы?
Я бы вместо этого использовал Attribute Routing. Таким образом, вам не придется использовать несколько маршрутов в WebApiConfig. Проверьте эту ссылку:docs.microsoft.com/en-us/aspnet/web-api/overview/…
@frapontillo: Идентификатор должен быть целым числом, чтобы он отличался от имени маршрута, в противном случае механизм маршрутизации будет рассматривать его как имя действия, а не как идентификатор. Если вам нужно иметь идентификатор в виде строки, вы можете создать действие.
0

action = action_name & quot; на URL и таким образом механизм маршрутизации знает, какое действие я хочу. Я также добавил атрибут ActionName к действиям, но не уверен, что он необходим.

1

api / Profiles & quot;)] на уровне контроллера и укажите маршрут в методе действия [Route (& lt; LikeProfile & quot;)]. Не нужно ничего менять в файле 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()
        {
        }
    }
}
5

Можно добавить несколько методов Get и Post в одном контроллере Web API. Здесь Маршрут по умолчанию вызывает проблему. Web API проверяет соответствие маршрута сверху вниз и, следовательно, ваш маршрут по умолчанию соответствует всем запросам. В соответствии с маршрутом по умолчанию в одном контроллере возможен только один метод Get и Post. Либо поместите следующий код сверху, либо закомментируйте / удалите маршрут по умолчанию

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

Лучшее и простое объяснение, которое я видел на эту тему - http://www.binaryintellect.net/articles/9db02aa1-c193-421e-94d0-926e440ed297.aspx

Edited -

Я работал только с Route и не нуждался в RoutePrefix.

Например, в контроллере

[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";
26

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

это больше не подход RESTful, но теперь вы можете называть свои действия по имени (вместо того, чтобы позволить Web API автоматически определять одно из них для вас на основе глагола), например так:

[POST] /api/VTRouting/TSPRoute

[POST] /api/VTRouting/Route

Вопреки распространенному мнению, в этом подходе нет ничего плохого, и он не злоупотребляет Web API. Вы по-прежнему можете использовать все удивительные функции Web API (делегирование обработчиков, согласование контента, средние форматы форматирования и т. Д.) - вы просто отказываетесь от подхода RESTful.

Это невозможно, тогда что-то еще должно быть неправильно настроено в вашем приложении. Можете ли вы показать все настройки маршрута? Также какexactly Вы называете действия контроллеров?
Спасибо за ответ, но он все еще дает мне ту же ошибку. Habib
сделал это, не работает Habib
Филип, я использую .Net Framework 4.5, с mvc4 или Visual studio 2012 RC. Какой шаблон вы используете для создания своего проекта, свой & apos; работает отлично Habib
Вся настройка маршрута находится в global.asax, у меня есть эта часть в моем вопросе. Для отправки запроса я использую Fiddler-> Compose- & gt; и выбрав Post в качестве операции Habib
-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 нарушает концепцию restfull api, но это работает. Если бы кто-нибудь мог пролить свет на этот вопрос. Что делать, если у меня есть URI как

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

так что, как вы могли видеть мой журнал, например, aggregateroot, хотя я могу определить другой контроллер для публикации исключительно и передать идентификационный номер публикации в моем URL, однако это дает гораздо больше смысла. поскольку моя публикация не существовала бы без самого журнала.

11

который принимает команды get / post / put / delete. этоnot нормальный контроллер MVC.

Обязательно, при/api/VTRouting может быть толькоone Метод HttpPost, который принимает отправляемые вами параметры. Название функцииdoes not matter, пока вы украшаете вещи [http]. Я никогда не пробовал, хотя.

Edit:  Это не работает. При разрешении кажется, что он идет по числу параметров, а не пытается привязать модель к типу.

You can overload the functions to accept different parameters. I am pretty sure you would be OK if you declared it the way you do, but used different (incompatible) parameters to the methods. If the params are the same, you are out of luck as model binding won't know which one you meant.

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

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

This part works

Шаблон по умолчанию, который они дают при создании нового, делает это довольно явным, и я бы сказал, что вы должны придерживаться этого соглашения:

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, нет особой причины не использовать стандартный шаблон контроллера / действия. Единственная реальная разница в том, что ваши сигнатуры методов не такие красивые, и вам нужноJson( returnValue) прежде чем вернуть их.

Edit:

Перегрузка прекрасно работает при использовании стандартного шаблона (отредактировано для включения) при использовании простых типов. Я пошел и протестировал и другой способ, с двумя пользовательскими объектами с разными сигнатурами. Никогда не мог заставить его работать.

Binding with complex objects doesn't look "deep", so thats a no-go You could get around this by passing an extra param, on the query string A better writeup than I can give on available options

В этом случае это сработало для меня, посмотрим, куда тебя это приведет. Исключение только для тестирования.

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' } )
Я предположил, что он попытается связать модель, чтобы найти ее, так как вы можете перегружать. Однако он работает с разными параметрами. Это может быть не так сложно переписать, чтобы сделать это, хотя, но они еще не выпустили исходный код, поэтому я просто застрял, глядя на некрасивую разборку
Я попытался изменить типы параметров, но кажется, что он позволяет только один метод Post в контроллере. Спасибо за ваш ответ Habib
+1 за фактическое объяснение причины, по которой он не работает, и философию веб-API.
25

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;
    }
}
Как будет выглядеть URL, чем звонитьRoute а такжеTSPRoute?
Да, так и должно быть. Благодарю.
по какой-то причине я не могу заставить это работать. это именно то, что я уже делал.
В каком пространстве имен находится Route? Я использую MVC4 и Маршрут не распознается.

Похожие вопросы