132

我开始使用 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/TSPRoute或者http://localhost:52370/api/VTRouting/Route 出现错误:

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

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

全球.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。

4

11 回答 11

148

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

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

  • 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}"
    );
    
于 2012-10-03T07:02:54.550 回答
47

您的问题的另一个解决方案是使用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;
    }
}
于 2015-11-26T23:43:56.917 回答
28

采用:

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 方法。

于 2012-07-10T07:02:52.423 回答
13

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 个具有不同签名的自定义对象。永远无法让它工作。

  • 与复杂对象的绑定看起来并不“深”,所以这是不行的
  • 您可以通过在查询字符串上传递一个额外的参数来解决这个问题
  • 比我可以提供的可用选项更好的文章

在这种情况下,这对我有用,看看它会带给你什么。仅用于测试的例外。

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' } )
于 2012-07-10T07:27:11.703 回答
6

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

    config.Routes.MapHttpRoute("API Default", 
                               "api/{controller}/{action}/{id}",
                               new { id = RouteParameter.Optional });
于 2015-04-04T05:48:42.330 回答
1

将路由前缀 [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()
        {
        }
    }
}
于 2016-09-10T07:30:41.713 回答
1

您可以使用这种方法:

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

    [HttpPost("TSPRoute")]
    public MyResult TSPRoute(MyRequestTemplate routingRequestTemplate)
    {
        return null;
    }
}
于 2020-07-03T21:55:52.873 回答
1

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

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

[HttpPost("Method2")]
public DataType Method2(MyRequestTemplate routingRequestTemplate){}
于 2022-01-11T11:59:56.723 回答
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 上设置身份验证/授权即可!

希望这可以帮助!

于 2015-01-14T11:50:39.200 回答
0

我在这个主题上看到的最好和最简单的解释 - 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";
于 2018-12-13T19:12:19.780 回答
-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

因此,您可能会看到我的日志类型是聚合根,尽管我可以单独定义另一个控制器用于发布,并在我的 url 中传递发布的 id 编号,但这更有意义。因为如果没有期刊本身,我的出版物就不会存在。

于 2012-07-12T11:51:59.243 回答