Web API 控制器中的多个 HttpPost 方法

我开始使用 MVC4 Web API 项目,我有控制器与多个 HttpPost方法。控制器看起来如下:

控制员

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


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

在这里,MyRequestTemplate表示负责处理通过请求传递的 Json 的模板类

错误:

当我使用 Fiddler 对 http://localhost:52370/api/VTRouting/TSPRoutehttp://localhost:52370/api/VTRouting/Route发出请求时,我得到一个错误:

找到了与请求匹配的多个操作

如果我删除上述方法之一,它工作正常。

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

我使用 POST 在 Fiddler 中发出请求,在 RequestBody 中为 MyRequestTemplate 传递 json。

205573 次浏览

用途:

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 的所有令人敬畏的特性(委托处理程序、内容协商、 mediatypeformat 等等)——您只需要抛弃 REST 式方法。

Web api 端点(控制器)是一个接受 get/post/put/delete 动词的单一资源。它是 没有一个普通的 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) {}
}

如果您想要创建一个能够做很多事情的类,对于 ajax 的使用,没有什么理由不使用标准的控制器/操作模式。唯一真正的区别是您的方法签名不那么漂亮,并且在返回它们之前必须用 Json( returnValue)包装它们。

编辑:

当使用简单类型时,使用标准模板(编辑后包含)时,重载工作正常。我也用另一种方法测试过,用两个具有不同签名的自定义对象。一直没能成功。

在这种情况下,这种方法对我很有效,看看它能带给你什么。只有测试例外。

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

所以你可能会看到我的日志聚合根排序,虽然我可以定义另一个控制器发布单独和传递 id 号码的发布在我的网址,但这给了更多的意义。因为我的出版物离不开杂志本身。

在一个控制器中可以有多个操作。

为此,你必须做以下两件事。

  • 首先使用 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;
    }
    }
    
  • 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}"
    );
    

我想这个问题已经有答案了。我还在寻找一个 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 上设置身份验证/授权就可以了!

希望这个能帮上忙!

可以在同一个 WebAPI 控制器中添加多个 Get 和 Post 方法。这里的默认路由导致问题。Web API 检查从上到下匹配路由,因此默认路由匹配所有请求。按照默认路由,在一个控制器中只能使用一个 Get 和 Post 方法。要么将下面的代码放在顶部,要么注释掉/删除默认路由

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

另一个解决方案是使用 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;
}
}

将 RoutePrefix [ RoutePrefix (“ api/Profiles”)]放在控制器级别,并将一个路由放在 action 方法[ 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()
{
}
}
}

我在这个话题上看到的最好和最简单的解释- 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";

您可以使用这种方法:

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


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

当创建另一个 Http 方法时,添加 [HttpPost("Description")]

[HttpPost("Method1")]
public DataType Method1(MyRequestTemplate routingRequestTemplate)
{
return null;
}


[HttpPost("Method2")]
public DataType Method2(MyRequestTemplate routingRequestTemplate){}