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

时间:2012-07-10 05:44:35

标签: c# asp.net-web-api global-asax asp.net-web-api-routing

我开始使用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。

11 个答案:

答案 0 :(得分:138)

您可以在一个控制器中执行多项操作。

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

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

答案 1 :(得分:31)

对您的问题更好的解决方案是使用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;
    }
}

答案 2 :(得分: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的所有强大功能(委派处理程序,内容协商,mediatype格式等) - 您只是放弃了RESTful方法。

答案 3 :(得分:11)

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)中。

修改

使用简单类型时,使用标准模板(编辑为包含)时,重载工作正常。我已经走了另一条路,用2个带有不同签名的自定义对象进行测试。永远不能让它发挥作用。

  • 与复杂对象的绑定看起来并不“深”,所以这是一个禁忌
  • 您可以通过在查询字符串
  • 上传递额外的参数来解决这个问题 关于可用选项的
  • A better writeup than I can give

在这种情况下,这对我有用,看看它在哪里。仅用于测试的例外情况。

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

答案 4 :(得分:6)

可以在同一个Web API Controller中添加多个Get和Post方法。默认路由是导致问题。 Web API检查从上到下的匹配路由,从而检查所有请求的默认路由匹配。根据默认路由,在一个控制器中只能使用一个Get和Post方法。将以下代码置于顶部或注释/删除默认路由

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

答案 5 :(得分:1)

将Route Prefix [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()
        {
        }
    }
}

答案 6 :(得分:1)

您可以使用这种方法:

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

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

答案 7 :(得分:0)

我刚刚在网址中添加了“action = action_name”,这样路由引擎知道我想要什么操作。我还将ActionName属性添加到了操作中,但我不确定是否需要它。

答案 8 :(得分:0)

我认为这个问题已经得到了回答。我也在寻找一些webApi控制器,它具有相同的标记但名称不同的mehtods。我试图将计算器实现为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上设置身份验证/授权即可完成!

希望这有帮助!

答案 9 :(得分:-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

因为你可能会看到我的期刊类似的聚合,但我可以单独定义另一个控制器进行发布,并在我的网址中传递发布的id号但是这更有意义。因为没有期刊本身,我的出版物就不存在了。

答案 10 :(得分:-1)

我在该主题上看到的最好,最简单的解释- http://www.binaryintellect.net/articles/9db02aa1-c193-421e-94d0-926e440ed297.aspx

  • 已编辑-

我只使用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";