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


243

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

找到多个符合请求的操作:webapi

我一直在寻找关于堆栈的其他类似问题,但我不明白。

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

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

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

Answers:


485

您的路线图可能是这样的:

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] in)。

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


以一种或另一种方式做有什么好处?如果执行辅助操作,是否只需将Http操作放在每个方法上?那是大的退缩吗?
chobo2 2013年

3
一个人是否比另一个人真正具有优势取决于您的项目。如果要构建RESTful api,则需要使用HTTP约定(GET,POST,PUT,DELETE ...)。在这种情况下,第一步是路由代码,但是对于通过api公开的每个实体,您都需要一个不同的控制器。根据您的方法名称,我猜测情况并非如此,因此请使用更具描述性的路由。当您的路线包括操作时,您将希望在每个方法上显式放置http属性。
2013年

1
@ chobo2为什么不只使用在控制器内相应命名的方法?GetSummary(MyVm wm)和GetDetails()
Jed

1
感谢您的回答,只是帮助我弄清楚了即使我的两个动作都使用了不同的名称,路由解析也无法正常工作的原因。我真的很困惑为什么不只是默认行为(即,为什么webapiconfig.cs中的默认路由模板不包含“ {action}”)!
2013年

1
@bruno(如果使用区域),您还可以在AdminAreaRegistration stackoverflow.com/a/9849011/16940
Simon_Weaver 2014年

67

从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)
{
    rturn null;
}

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

其中ControllerName是控制器的名称(不带“ controller”)。这样,您便可以使用上述详细路线进行每项操作。

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


我真的很喜欢这个解决方案。我的默认路由仍然相同,并且有一条例外的“例外”路由
Leandro De Mello Fagundes

您还可以将参数映射到URL EX中:[Route(“ api / ControllerName / Summary / {vm}”)]
nulltron

15

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

MyVm看起来像一个复杂的对象,由格式化程序从主体读取,因此就路由数据而言,您有两种相同的方法(因为它们都不具有来自路由的任何参数)-这使得调度程序(IHttpActionSelector)无法匹配适当的方法。

您需要通过querystring或route参数来区分它们,以解决歧义。


14

经过大量的网上搜索并尝试找到最适合的路线图形式(如果已找到以下内容)

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)


9
对我来说,这可行,但只有在更改了路线配置中的路线顺序后,才有行动的人首先出现
Fredrik Stolpe 2015年

确切的顺序在这里很重要
2015年


5

如果不使用操作,则选项为:

  1. 将其中一种方法移至其他控制器,以免冲突。

  2. 仅使用采用该参数的一种方法,如果为null,则从您的代码中调用另一种方法。


这可能是解决方案,但不是最佳解决方案,无论如何我这边是+1 :)
satish kumar V

4

这个解决方案对我有用。

请首先将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

4

这是每个知道一切正确并检查了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个小时。


1
谢谢,您为我节省了大约3个小时
geedubb,

3

我发现当我有两个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 }
);

3

由于使用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;

2

请检查您有两种名称不同且参​​数相同的方法。

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


2

我在尝试用额外的操作来扩充我的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调用的路由与对额外动作的调用分开。


2

就我而言,一切都是正确的

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

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


这个答案对我很有帮助!
tvb108108

1

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

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


0

确保不使用[HttpPost / Put / Get / Delete]属性为默认的GET | PUT | POST | DELETE操作修饰Controller方法。我已将这张礼物添加到我的香草Post控制器动作中,并导致404。

希望这会对某人有所帮助,因为这可能会令人沮丧并导致进度暂停。


0

例如=> TestController

        [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
            );

而已 :)

结果: 在此处输入图片说明


0

您是否尝试过像:

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

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

1
由于该HttpGet属性没有接受字符串参数的构造函数,因此无法在非.NET Core项目中进行编译。
Hoppeduppeanut
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.