C# 为什么我会得到;发现多个操作……”;当我有一个动作后?

C# 为什么我会得到;发现多个操作……”;当我有一个动作后?,c#,asp.net-mvc,asp.net-web-api,asp.net-web-api2,asp.net-web-api-routing,C#,Asp.net Mvc,Asp.net Web Api,Asp.net Web Api2,Asp.net Web Api Routing,MyFBMessageController只有以下方法: public string Get() { ... } [ChildActionOnly] public SendResponse Send(ComplexType msg) { ... } [ChildActionOnly] public SendResponse SendImage(string x, string y) { ... } [HttpPost] public SendResponse Post([FromBody]

My
FBMessageController
只有以下方法:

public string Get() { ... }

[ChildActionOnly]
public SendResponse Send(ComplexType msg) { ... }

[ChildActionOnly]
public SendResponse SendImage(string x, string y) { ... }

[HttpPost]
public SendResponse Post([FromBody]AnotherComplexType yyy) { ... }

public void Put(..) { ... }

public void Delete(..) { ... }
但是,当我尝试使用POST to
../api/fbMessage
发送请求时

我得到以下例外情况:

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

WebApiConfig.Register
包含默认代码:

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

导致错误的原因是什么?

您是否可以尝试使用这样的属性来装饰您的所有操作,以查看是否有任何更改

[HttpGet]
public string Get() { ... }

[ChildActionOnly]
public SendResponse Send(..) { ... }

[ChildActionOnly]
public SendResponse SendImage(..) { ... }

[HttpPost]
public SendResponse Post([FromBody]xxx yyy) { ... }

[HttpPut]
public void Put(..) { ... }

[HttpDelete]
public void Delete(..) { ... }

可能是您的Put和Post在某种程度上存在冲突。

虽然您似乎已经隔离了问题,但我执行了以下集成测试来重新创建您的问题,并帮助解释导致错误的原因

[TestClass]
public class FBMessageControllerTests {
    [TestMethod]
    public async Task HttpClient_Should_Get_OKStatus_From_Post_To_FBMessage() {

        using (var server = new TestServer()) {

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


            var handlerMock = new Mock<IExceptionHandler>();
            handlerMock
                .Setup(m => m.HandleAsync(It.IsAny<ExceptionHandlerContext>(), It.IsAny<System.Threading.CancellationToken>()))
                .Callback<ExceptionHandlerContext, CancellationToken>((context, token) => {
                    var innerException = context.ExceptionContext.Exception;

                    Assert.Fail(innerException.Message);
                });
            config.Services.Replace(typeof(IExceptionHandler), handlerMock.Object);



            var client = server.CreateClient();

            string url = "http://localhost/api/fbMessage";

            var body = new { body = "Hello World" };

            using (var response = await client.PostAsJsonAsync(url, body)) {
                var message = await response.Content.ReadAsStringAsync();
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode, message);
            }
        }
    }

    [Authorize]
    public class FBMessageController : ApiController {
        public string Get() {
            return null;
        }

        [System.Web.Mvc.ChildActionOnly]
        public SendResponse Send(ComplexType test) {
            return null;
        }

        [System.Web.Mvc.ChildActionOnly]
        public SendResponse SendImage(string x, string y) {
            return null;
        }

        [HttpPost]
        public SendResponse Post([FromBody]AnotherComplexType body) {
            return null;
        }

        public void Put(string gbody) {
            return;
        }

        public void Delete(string body) {
            return;
        }
    }

    public class SendResponse { }
    public class ComplexType {  }
    public class AnotherComplexType {  }
}
id参数绑定到URI。因此,这一行动只能 在路由中匹配包含“id”值的URI 查询字符串中的字典或

可选参数是一个例外,因为它们是可选的。对于 一个可选参数,如果绑定无法从 URI

复杂类型是一个例外,原因不同。复杂类型 只能通过自定义绑定绑定到URI。但是在这种情况下,, 框架无法预先知道参数是否会绑定 指向特定的URI。要找到答案,它需要调用绑定。 选择算法的目标是从 静态描述,然后再调用任何绑定。因此,复杂 类型被排除在匹配算法之外。

选择操作后,将调用所有参数绑定

总结:

  • 该操作必须与请求的HTTP方法匹配
  • 操作名称必须与路由字典中的“操作”条目(如果存在)匹配
  • 对于操作的每个参数,如果参数取自URI,则必须在路由中找到参数名称 字典或URI查询字符串中的。(可选参数和 不包括具有复杂类型的参数。)
  • 尝试匹配最多数量的参数。最佳匹配可能是没有参数的方法
希望这能帮助您理解为什么会收到“发现多个操作…”的消息


快乐编码

如果未明确定义HTTP方法属性,则默认为POST。因此,Send()也被视为post方法,由于发现多个操作,因此会发生异常


您可以尝试安装调试路由器工具,以直观地了解如何选择控制器和操作。以下是

异常消息通常会告诉您哪些操作冲突。检查是否有任何内部异常可以为您提供线索。查看此疑难解答思路:尽管“发送”和“发送图像”没有标记为“Post”,但它们可能通过Http Post进行通信,并且可能与“Post”方法具有相同的“签名”。。使用Fiddler并注释掉'Send'和'SendImage',看看这是否是追求的途径。@SRQCoder我也在想同样的事情。正在查找文档,查看Send是否是公约在选择选项时使用的特殊名称之一。@OldGeezer。您似乎混合了Web API和MVC属性,因为
System.Web.MVC.ChildActionOnly
是MVC属性,而不是Web属性API@Nikosi,谢谢你的奉献。请原谅我的缓慢,但我仍然不知道是哪个选择标准导致
Send
成为另一个匹配操作。我认为,如果没有明确地修饰,默认的Http方法是Get?使用第一个条件是否会消除
Send
?另外,my
ComplexType
与另一个ComplexType非常不同,Send和Post是可以在约定中互换使用的操作名称。此外,这两个操作都有一个复杂的参数类型,在尝试匹配参数时会将其排除在外。我将在与你的评论相关的部分加粗。
public void Get(int id)