【问题标题】:Multiple actions were found that match the request in Web Api在 Web Api 中找到多个与请求匹配的操作
【发布时间】:2013-01-26 05:27:51
【问题描述】:

当我尝试使用 2 个“获取”方法时,我不断收到此错误

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

我一直在查看有关堆栈的其他类似问题,但我不明白。

我有 2 个不同的名称并使用“HttpGet”属性

[HttpGet]
public HttpResponseMessage Summary(MyVm vm)
{
    return null;
}

[HttpGet]
public HttpResponseMessage FullDetails()
{
    return null;
}

【问题讨论】:

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


    【解决方案1】:

    您的路线图在 WebApiConfig.cs 中可能是这样的:

    routes.MapHttpRoute(
    name: "API Default",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional });
    

    但是为了使用相同的 http 方法进行多个操作,您需要通过如下路径向 webapi 提供更多信息:

    routes.MapHttpRoute(
    name: "API Default",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional });
    

    注意 routeTemplate 现在包含一个动作。更多信息在这里:http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

    更新:

    好吧,现在我想我明白了你的目的是什么:

    也许你不需要action url参数,应该用另一种方式描述你所追求的内容。既然您说这些方法从同一实体返回数据,那么只需让参数为您进行描述。

    例如你的两种方法可以变成:

    public HttpResponseMessage Get()
    {
        return null;
    }
    
    public HttpResponseMessage Get(MyVm vm)
    {
        return null;
    }
    

    你在 MyVm 对象中传递什么样的数据?如果您只能通过 URI 传递变量,我建议您走这条路线。否则,您需要在请求的正文中发送对象,而在执行 GET 时这不是很 HTTP(尽管它可以工作,只需在 MyVm 前面使用 [FromBody])。

    希望这说明您可以在单个控制器中拥有多个 GET 方法,而无需使用操作名称甚至 [HttpGet] 属性。

    【讨论】:

    • 用一种方法或另一种方法有什么好处吗?如果我做次要,我只需要在每个方法上放置 Http 操作吗?这是最大的缺点吗?
    • 一个是否比另一个更有优势真的取决于你的项目。如果您正在构建一个 RESTful api,那么您将需要使用 HTTP 约定(GET、POST、PUT、DELETE...)。在这种情况下,第一个路由代码块是要走的路,但是您需要为通过 api 公开的每个实体使用不同的控制器。根据您的方法名称,我猜情况并非如此,因此请使用更具描述性的路由。当您的路由包含操作时,您需要明确地将 http 属性放在每个方法上。
    • @chobo2 为什么不直接使用控制器中相应命名的方法呢? GetSummary(MyVm wm) 和 GetDetails()
    • 感谢您的回答,只是帮助我弄清楚了为什么即使我的两个操作名称不同,路由解析也不起作用。我真的很困惑为什么不只是默认行为(即为什么 webapiconfig.cs 中的默认路由模板不包含“{action}”)!
    • @bruno 如果使用区域,您还可以在 AdminAreaRegistration stackoverflow.com/a/9849011/16940 中添加像这样的“管理员”特定 API
    【解决方案2】:

    从 Web API 2 开始更新。

    在您的 WebApiConfig.cs 文件中使用此 API 配置:

    public static void Register(HttpConfiguration config)
    {
        //// Web API routes
        config.MapHttpAttributeRoutes(); //Don't miss this
    
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = System.Web.Http.RouteParameter.Optional }
        );
    }
    

    您可以像这样路由我们的控制器:

    [Route("api/ControllerName/Summary")]
    [HttpGet]
    public HttpResponseMessage Summary(MyVm vm)
    {
        return null;
    }
    
    [Route("api/ControllerName/FullDetails")]
    [HttpGet]
    public HttpResponseMessage FullDetails()
    {
        return null;
    }
    

    其中 ControllerName 是您的控制器的名称(不含“控制器”)。这将允许您使用上面详述的路线获取每个操作。

    进一步阅读:http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

    【讨论】:

    • 我真的很喜欢这个解决方案。我的默认路线仍然相同,并且我有一个例外的“例外”路线
    • 也可以将参数映射到url EX: [Route("api/ControllerName/Summary/{vm}")]
    【解决方案3】:

    在 Web API(默认情况下)中,方法是根据 HTTP 方法和路由值的组合选择的

    MyVm 看起来像一个复杂的对象,由格式化程序从正文中读取,因此您在路由数据方面有两个相同的方法(因为它们都没有来自路由的任何参数) - 这使得调度程序( IHttpActionSelector) 来匹配合适的。

    您需要通过查询字符串或路由参数来区分它们以解决歧义。

    【讨论】:

      【解决方案4】:

      经过大量的网络搜索并试图找到最适合路由图的形式 如果发现以下

      config.Routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id =RouteParameter.Optional }, new { id = @"\d+" });
      config.Routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");
      

      这些映射适用于动作名称映射和基本 http 约定(GET、POST、PUT、DELETE)

      【讨论】:

      • 对我来说这行得通,但只有在更改路由配置中的路由顺序之后,才能首先出现具有操作的路由
      • 这里的顺序很重要
      【解决方案5】:

      这是给所有知道一切都正确并检查了50次的人的答案.....

      确保您没有重复查看RouteConfig.cs

      您要编辑的文件名为WebApiConfig.cs

      此外,它应该看起来完全像这样:

      using System.Web.Http;
      
      namespace My.Epic.Website
      {
          public static class WebApiConfig
          {
              public static void Register(HttpConfiguration config)
              {
                config.MapHttpAttributeRoutes();
      
                // api/Country/WithStates
                config.Routes.MapHttpRoute(
                  name: "ControllerAndActionOnly",
                  routeTemplate: "api/{controller}/{action}",
                  defaults: new { },
                  constraints: new { action = @"^[a-zA-Z]+([\s][a-zA-Z]+)*$" });
      
                config.Routes.MapHttpRoute(
                  name: "DefaultActionApi",
                  routeTemplate: "api/{controller}/{action}/{id}",
                  defaults: new { id = RouteParameter.Optional }
                );
          }
          }
      }
      

      我本可以为自己节省大约 3 个小时。

      【讨论】:

      • 谢谢,你帮我节省了大约 3 个小时
      • 老兄。这无疑为我节省了几个小时。谢谢!
      【解决方案6】:

      您的网络方法可能被解析为相同的 url。看看下面的链接:-

      http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

      因此,您可能需要将方法名称添加到路由表中。

      【讨论】:

        【解决方案7】:

        如果不使用操作,选项将是:

        1. 将其中一种方法移至不同的控制器,以免它们发生冲突。

        2. 只使用一种获取参数的方法,如果它为 null,请从您的代码中调用另一种方法。

        【讨论】:

        • 这可能是解决方案,但不是最佳解决方案,无论如何 +1 从我这边 :)
        【解决方案8】:

        这个解决方案对我有用。

        请把 Route2 先放在 WebApiConfig 中。还要在每个方法前添加 HttpGet 和 HttpPost,并在 url 中包含控制器名称和方法名称。

        WebApiConfig =>

        config.Routes.MapHttpRoute(
                   name: "MapByAction",
                   routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional });
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional });
        

        控制器 =>

        public class ValuesController : ApiController
        {
        
            [HttpPost]
            public string GetCustomer([FromBody] RequestModel req)
            {
                return "Customer";
            }
        
            [HttpPost]
            public string GetCustomerList([FromBody] RequestModel req)
            {
                return "Customer List";
            }
        }
        

        网址 =>

        http://localhost:7050/api/Values/GetCustomer
        
        http://localhost:7050/api/Values/GetCustomerList
        

        【讨论】:

          【解决方案9】:

          我发现当我有两个 Get 方法时,一个是无参数的,一个是复杂类型作为参数的,我得到了同样的错误。我通过添加一个名为 Id 的 int 类型的虚拟参数作为我的第一个参数,然后是我的复杂类型参数来解决这个问题。然后我将复杂类型参数添加到路由模板中。以下对我有用。

          先拿到:

          public IEnumerable<SearchItem> Get()
          {
          ...
          }
          

          第二次获得:

          public IEnumerable<SearchItem> Get(int id, [FromUri] List<string> layers)
          {
          ...
          }
          

          WebApiConfig:

          config.Routes.MapHttpRoute(
              name: "DefaultApi",
              routeTemplate: "api/{controller}/{id}/{layers}",
              defaults: new { id = RouteParameter.Optional, layers RouteParameter.Optional }
          );
          

          【讨论】:

            【解决方案10】:

            这可能是由于使用 MVC 控制器而不是 Web API 控制器。 检查 Web API 控制器中的命名空间,它应该如下所示

            using System.Net;
            using System.Net.Http;
            using System.Web.Http;
            

            如果命名空间如下,则在 web api 控制器方法调用中给出上述错误

            using System.Web;
            using System.Web.Mvc;
            

            【讨论】:

              【解决方案11】:

              请检查您有两个名称不同但参数相同的方法。

              如果是这样,请删除任何方法并尝试。

              【讨论】:

                【解决方案12】:

                我在尝试通过额外的操作来增强我的 WebAPI 控制器时偶然发现了这个问题。

                假设你有

                public IEnumerable<string> Get()
                {
                    return this.Repository.GetAll();
                }
                
                [HttpGet]
                public void ReSeed()
                {
                    // Your custom action here
                }
                

                现在有两种方法可以满足/api/controller的请求,触发TS描述的问题。

                我不想将“虚拟”参数添加到我的附加操作中,因此我研究了默认操作并提出了:

                [ActionName("builtin")]
                public IEnumerable<string> Get()
                {
                    return this.Repository.GetAll();
                }
                

                对于结合“双”路由绑定的第一种方法:

                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { action = "builtin", id = RouteParameter.Optional },
                    constraints: new { id = @"\d+" });
                
                config.Routes.MapHttpRoute(
                    name: "CustomActionApi",
                    routeTemplate: "api/{controller}/{action}");
                

                请注意,即使第一个路由模板中没有“action”参数,您仍然可以配置默认操作,允许我们将“正常”WebAPI 调用的路由和对额外操作的调用分开。

                【讨论】:

                  【解决方案13】:

                  在我的情况下,一切都是正确的

                  1) Web Config 配置正确 2) 路由前缀和路由属性正确

                  我仍然收到错误消息。在我的案例中,“Route”属性(通过按 F12)指向 System.Web.MVc 而不是 System.Web.Http 导致问题。

                  【讨论】:

                  • 这个答案对我帮助很大!
                  【解决方案14】:

                  您可以将[Route("api/[controller]/[action]")] 添加到您的控制器类中。

                  [Route("api/[controller]/[action]")]
                  [ApiController]
                  public class MySuperController : ControllerBase
                  {
                   ...
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    我知道这是一个老问题,但有时,当您使用 AngularJS 等服务资源连接到 WebAPI 时,请确保您使用的是正确的路由,否则会发生此错误。

                    【讨论】:

                      【解决方案16】:

                      请确保不要使用 [HttpPost/Put/Get/Delete] 属性为默认的 GET|PUT|POST|DELETE 操作装饰控制器方法。我已将此属性添加到我的原始后控制器操作中,它导致了 404。

                      希望这对某人有所帮助,因为它可能会非常令人沮丧并导致进展停滞。

                      【讨论】:

                        【解决方案17】:

                        例如 => 测试控制器

                                [HttpGet]
                                public string TestMethod(int arg0)
                                {
                                    return "";
                                }
                        
                                [HttpGet]
                                public string TestMethod2(string arg0)
                                {
                                    return "";
                                }
                        
                                [HttpGet]
                                public string TestMethod3(int arg0,string arg1)
                                {
                                    return "";
                                }
                        

                        如果只能更改 WebApiConfig.cs 文件。

                         config.Routes.MapHttpRoute(
                                        name: "DefaultApi",
                                        routeTemplate: "api/{controller}/{action}/",
                                        defaults: null
                                    );
                        

                        就是这样:)

                        结果:

                        【讨论】:

                          【解决方案18】:

                          你有没有尝试过:

                          [HttpGet("Summary")]
                          public HttpResponseMessage Summary(MyVm vm)
                          {
                              return null;
                          }
                          
                          [HttpGet("FullDetails")]
                          public HttpResponseMessage FullDetails()
                          {
                              return null;
                          }
                          

                          【讨论】:

                          • 这不会在非 .NET Core 项目中编译,因为 HttpGet 属性没有接受字符串参数的构造函数。
                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2016-04-08
                          • 1970-01-01
                          • 2015-05-01
                          • 2016-07-31
                          • 2018-06-28
                          相关资源
                          最近更新 更多