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

Hab*_*bib 126 c# global-asax asp.net-web-api 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里MyRequestTemplate表示负责处理通过请求的Json的模板类.

错误:

当我让使用招为请求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" }
    );
}
Run Code Online (Sandbox Code Playgroud)

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

Asi*_*taq 144

您可以在单个控制器中执行多个操作.

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

  • 首先使用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;
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 其次,在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}"
    );
    
    Run Code Online (Sandbox Code Playgroud)

  • @frapontillo:Id应该是一个integeter,因此它会从路由名称中删除,否则routing enghine会将其视为动作名称而不是id.如果您需要将id作为字符串,则可以创建操作. (5认同)
  • 我们需要检查的任何其他东西,它不是工作 (3认同)

Wis*_*kas 37

对您的问题更好的解决方案是使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 与调用`Route`和`TSPRoute`相比,URL看起来如何? (2认同)

Fil*_*p W 27

使用:

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

它不再是RESTful方法,但您现在可以通过名称调用您的操作(而不是让Web API根据动词自动为您确定一个),如下所示:

[POST] /api/VTRouting/TSPRoute

[POST] /api/VTRouting/Route
Run Code Online (Sandbox Code Playgroud)

与流行的看法相反,这种方法没有任何问题,也没有滥用Web API.您仍然可以利用Web API的所有强大功能(委派处理程序,内容协商,mediatype格式等) - 您只是放弃了RESTful方法.


And*_*ker 12

Web api端点(控制器)是接受get/post/put/delete动词的单个资源.它不是普通的MVC控制器.

必然,/api/VTRouting只有一个 HttpPost方法接受您发送的参数.只要您使用[http]内容进行装饰,函数名称无关紧要.不过,我从未尝试过.

编辑: 这不起作用.在解析时,它似乎是通过参数的数量,而不是尝试模型绑定到类型.

您可以重载函数以接受不同的参数.如果你按照你的方式声明它,我很确定你会好的,但是对方法使用了不同的(不兼容的)参数.如果params是相同的,那么你运气不好,因为模型绑定不会知道你的意思.

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

[HttpPost]
public MyResult TSPRoute(MyOtherTemplate routingRequestTemplate) {...}
Run Code Online (Sandbox Code Playgroud)

这部分有效

他们创建一个新模板时给出的默认模板使这个非常明确,我想你应该坚持这个约定:

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) {}
}
Run Code Online (Sandbox Code Playgroud)

如果你想创建一个做很多事情的类,对于ajax使用,没有很大的理由不使用标准的控制器/动作模式.唯一真正的区别是你的方法签名不是很漂亮,你必须在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; }
}
Run Code Online (Sandbox Code Playgroud)

并且这样调用控制台:

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

  • +1实际解释它不起作用的原因,以及web api背后的哲学. (2认同)

小智 6

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

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