C# Web API 控制器中的多个 HttpPost 方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11407267/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple HttpPost method in Web API controller
提问by Habib
I am starting to use MVC4 Web API project, I have controller with multiple HttpPostmethods. The Controller looks like the following:
我开始使用 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 MyRequestTemplaterepresents the template class responsible for handling the Json coming through the request.
这里MyRequestTemplate表示负责处理来自请求的 Json 的模板类。
Error:
错误:
When I make a request using Fiddler for http://localhost:52370/api/VTRouting/TSPRouteor http://localhost:52370/api/VTRouting/RouteI get an error:
当我使用 Fiddler 发出请求时,http://localhost:52370/api/VTRouting/TSPRoute或http://localhost:52370/api/VTRouting/Route出现错误:
Multiple actions were found that match the request
找到多个与请求匹配的操作
If I remove one of the above method it works fine.
如果我删除上述方法之一,它工作正常。
Global.asax
全球.asax
I have tried modifying the default routing table in global.asax, but I am still getting the error, I think I have problem in defining routes in global.asax. Here is what I am doing in 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" }
);
}
I am making the request in Fiddler using POST, passing json in RequestBody for MyRequestTemplate.
我正在使用 POST 在 Fiddler 中发出请求,在 RequestBody 中为 MyRequestTemplate 传递 json。
采纳答案by Asif Mushtaq
You can have multiple actions in a single controller.
您可以在单个控制器中执行多个操作。
For that you have to do the following two things.
为此,您必须做以下两件事。
First decorate actions with
ActionNameattribute 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
WebApiConfigfile.// 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}" );
首先用
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}" );
回答by Filip W
use:
用:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
it's not a RESTful approach anymore, but you can now call your actions by name (rather than let the Web API automatically determine one for you based on the verb) like this:
它不再是一种 RESTful 方法,但您现在可以按名称调用您的操作(而不是让 Web API 根据动词自动为您确定一个),如下所示:
[POST] /api/VTRouting/TSPRoute
[POST] /api/VTRouting/Route
Contrary to popular belief, there is nothing wrong with this approach, and it's not abusing Web API. You can still leverage on all the awesome features of Web API (delegating handlers, content negotiation, mediatypeformatters and so on) - you just ditch the RESTful approach.
与流行的看法相反,这种方法没有任何问题,而且它没有滥用 Web API。您仍然可以利用 Web API 的所有出色功能(委托处理程序、内容协商、媒体类型格式化程序等)——您只需放弃 RESTful 方法。
回答by Andrew Backer
A web api endpoint (controller) is a single resource that accepts get/post/put/delete verbs. It is nota normal MVC controller.
Web api 端点(控制器)是接受 get/post/put/delete 动词的单个资源。它不是一个普通的 MVC 控制器。
Necessarily, at /api/VTRoutingthere can only be oneHttpPost method that accepts the parameters you are sending. The function name does not matter, as long as you are decorating with the [http] stuff. I've never tried, though.
必然地,/api/VTRouting只能有一个HttpPost 方法接受您发送的参数。函数名无所谓,只要你用 [http] 的东西来装饰。不过我从来没试过。
Edit:This does not work. In resolving, it seems to go by the number of parameters, not trying to model-bind to the type.
编辑:这不起作用。在解析时,它似乎按照参数的数量进行,而不是尝试将模型绑定到类型。
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
这部分工作
The default template they give when you create a new one makes this pretty explicit, and I would say you should stick with this convention:
当您创建新模板时,他们提供的默认模板使这一点非常明确,我想说您应该坚持这个约定:
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) {}
}
If you want to make one class that does many things, for ajax use, there is no big reason to not use a standard controller/action pattern. The only real difference is your method signatures aren't as pretty, and you have to wrap things in Json( returnValue)before you return them.
如果你想创建一个可以做很多事情的类,对于 ajax 的使用,没有很大的理由不使用标准的控制器/动作模式。唯一真正的区别是你的方法签名不那么漂亮,你必须在Json( returnValue)返回它们之前包装东西。
Edit:
编辑:
Overloading works just fine when using the standard template (edited to include) when using simple types. I've gone and tested the other way too, with 2 custom objects with different signatures. Never could get it to work.
在使用简单类型时使用标准模板(编辑为包含)时,重载工作得很好。我也以另一种方式进行了测试,使用了 2 个具有不同签名的自定义对象。永远无法让它发挥作用。
- 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 giveon available options
This worked for me in this case, see where it gets you. Exception for testing only.
在这种情况下,这对我有用,看看它让你在哪里。仅用于测试的例外情况。
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; }
}
And called like this form the console:
并像这样从控制台调用:
$.post("/api/Nerdy?type=white", { 'Name':'Slim', 'Age':'21' } )
回答by mobygeek
public class Journal : ApiController
{
public MyResult Get(journal id)
{
return null;
}
}
public class Journal : ApiController
{
public MyResult Get(journal id, publication id)
{
return null;
}
}
I am not sure whether overloading get/post method violates the concept of restfull api,but it workds. If anyone could've enlighten on this matter. What if I have a uri as
我不确定重载 get/post 方法是否违反了 restfull api 的概念,但它有效。如果有人能在这件事上有所启发。如果我有一个 uri 怎么办
uri:/api/journal/journalid
uri:/api/journal/journalid/publicationid
so as you might seen my journal sort of aggregateroot, though i can define another controller for publication solely and pass id number of publication in my url however this gives much more sense. since my publication would not exist without journal itself.
所以你可能会看到我的日志有点聚合根,虽然我可以单独定义另一个控制器来发布,并在我的 url 中传递发布的 id 号,但这更有意义。因为如果没有期刊本身,我的出版物就不会存在。
回答by Rony Tesler
I just added "action=action_name" to the url and this way the routing engine knows what action I want. I also added the ActionName Attribute to the actions but I'm not sure it's needed.
我刚刚在 url 中添加了“action=action_name”,这样路由引擎就知道我想要什么操作。我还在操作中添加了 ActionName 属性,但我不确定是否需要它。
回答by Yawar Murtaza
I think the question has already been answered. I was also looking for something a webApi controller that has same signatured mehtods but different names. I was trying to implement the Calculator as WebApi. Calculator has 4 methods with the same signature but different names.
我想这个问题已经得到了回答。我也在寻找具有相同签名方法但名称不同的 webApi 控制器。我试图将计算器实现为 WebApi。Calculator 有 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);
}
}
and in the WebApiConfig file you already have
并且在您已经拥有的 WebApiConfig 文件中
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
Just set the authentication / authorisation on IIS and you are done!
只需在 IIS 上设置身份验证/授权即可完成!
Hope this helps!
希望这可以帮助!
回答by Shahid Ullah
It is Possible to add Multiple Get and Post methods in the same Web API Controller. Here default Route is Causing the Issue. Web API checks for Matching Route from Top to Bottom and Hence Your Default Route Matches for all Requests. As per default route only one Get and Post Method is possible in one controller. Either place the following code on top or Comment Out/Delete Default Route
可以在同一个 Web API 控制器中添加多个 Get 和 Post 方法。这里默认路由是导致问题。Web API 检查从上到下的匹配路由,因此所有请求的默认路由匹配。根据默认路由,在一个控制器中只能使用一种 Get 和 Post 方法。将以下代码放在顶部或注释掉/删除默认路由
config.Routes.MapHttpRoute("API Default",
"api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
回答by Wisienkas
A much better solution to your problem would be to use Routewhich lets you specify the route on the method by annotation:
一个更好的解决您的问题的方法是使用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;
}
}
回答by Sushil Kumar
Put Route Prefix [RoutePrefix("api/Profiles")] at the controller level and put a route at action method [Route("LikeProfile")]. Don't need to change anything in global.asax file
将路由前缀 [RoutePrefix("api/Profiles")] 放在控制器级别,并将路由放在操作方法 [Route("LikeProfile")] 中。不需要更改 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()
{
}
}
}
回答by Howard Shlom
Best and simplest explanation I have seen on this topic - http://www.binaryintellect.net/articles/9db02aa1-c193-421e-94d0-926e440ed297.aspx
我在这个主题上看到的最好和最简单的解释 - http://www.binaryintellect.net/articles/9db02aa1-c193-421e-94d0-926e440ed297.aspx
- Edited -
- 编辑 -
I got it working with only Route, and did not need RoutePrefix.
我只使用 Route,不需要 RoutePrefix。
For example, in the controller
例如,在控制器中
[HttpPost]
[Route("[action]")]
public IActionResult PostCustomer
([FromBody]CustomerOrder obj)
{
}
and
和
[HttpPost]
[Route("[action]")]
public IActionResult PostCustomerAndOrder
([FromBody]CustomerOrder obj)
{
}
Then, the function name goes in jquery as either -
然后,函数名称在 jquery 中作为 -
options.url = "/api/customer/PostCustomer";
or
或者
options.url = "/api/customer/PostCustomerAndOrder";

