1

Мой 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 для .../api/fbMessage,

я получаю следующее исключение:

«Mutliple были найдены действия, соответствующие запросу «

WebApiConfig.Register содержит код по умолчанию:

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

Что вызывает ошибка?

+0

Сообщение об исключении обычно сообщает вам, какие действия противоречили друг другу. проверьте, есть ли какие-либо внутренние исключения, которые дают вам ключ. – Nkosi

+0

взгляните на это http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api – Nkosi

+1

Устранение неполадок Идея: хотя «Отправить» и «SendImage» не помечены как «Post», они могут общаться через Http Post - и могут иметь такую ​​же «подпись», что и метод «Post». Используйте Fiddler, а также комментируйте «Отправить» и «SendImage», чтобы узнать, это путь к продолжению. –

ответ

0

Хотя вы, похоже, уже выделили проблему, я выполнил следующий интеграционный тест, чтобы воссоздать вашу проблему и объяснить причину ошибки.

[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 { } 
} 

Который произвел следующий результат сообщение: были найдены

несколько действий, которые соответствуют запросу:
Отправить на MiscUnitTests типа + FBMessageControllerTests + FBMessageController
Сообщение от MiscUnitTests типа + FBMessageControllerTests + FBMessageController

Приведенное выше сообщение сообщает вам, в чем именно была проблема. Структура обычно говорит вам, почему вы получили определенные ошибки. Иногда вам нужно знать, где искать.

Ссылка на следующие Routing and Action Selection in ASP.NET Web API, вот почему у вас возникла проблема.

вот алгоритм выбора действия.

  1. Создайте список всех действий на контроллере, соответствующих методу HTTP-запроса.
  2. Если в словаре маршрута есть запись «действие», удалите действия, имя которых не соответствует этому значению.
  3. Постарайтесь, чтобы соответствовать параметрам действия к URI, следующим образом:
    • Для каждого действия, получить список параметров, которые являются простым типом, где связывание получает параметр из URI. Исключить необязательные параметры.
    • Из этого списка попытайтесь найти соответствие для каждого имени параметра либо в словаре маршрута, либо в строке запроса URI. Матчи: нечувствительны к регистру и не зависят от порядка параметров.
    • Выберите действие, в котором каждый параметр в списке имеет совпадение в URI.
    • Если больше одного действия соответствует этим критериям, выберите тот, который соответствует большинству параметров.
  4. Игнорировать действия с атрибутом [NonAction].

Шаг 3, вероятно, является самым запутанным. Основная идея заключается в том, что параметр может получить свое значение либо из URI, либо из тела запроса , либо из пользовательской привязки. Для параметров, которые поступают из URI, , мы хотим убедиться, что URI фактически содержит значение для этого параметра , либо в пути (через словарь маршрута), либо в строке запроса .

В качестве примера рассмотрим следующее действие:

параметр
public void Get(int id) 

Идентификатор связывается с URI. Следовательно, это действие может только соответствовать URI, который содержит значение для «id», либо в словаре маршрута , либо в строке запроса.

Необязательные параметры являются исключением, поскольку они являются необязательными. Для необязательный параметр, это нормально, если привязка не может получить значение от URI.

Сложные типы являются исключением по другой причине. Сложный тип может связываться только с URI посредством пользовательской привязки. Но в этом случае структура не может заранее знать, будет ли параметр связывать с конкретным URI. Чтобы узнать это, нужно будет вызвать привязку. Целью алгоритма выбора является выбор действия из статического описания перед вызовом любых привязок. Поэтому из алгоритма сопоставления исключаются сложные типы .

После того, как действие выбрано, вызывается все привязки параметров.

Резюме:

  • Действие должно соответствовать методу HTTP запроса.
  • Имя действия должно соответствовать записи «действие» в словаре маршрута, если имеется.
  • Для каждого параметра действия, если параметр берется из URI, имя параметра должно быть найдено либо в словаре маршрута , либо в строке запроса URI. (Необязательные параметры и параметры исключаются.)
  • Постарайтесь сопоставить максимальное количество параметров. Лучшим совпадением может быть метод без параметров.

Надеется, что это поможет вам понять, почему вы получили «Множественные действия были найдены ...» сообщение.

Счастливое кодирование !!!

+0

@ Никоси, спасибо за вашу преданность делу. Простите мою медлительность, но я до сих пор не понимаю, какие критерии выбора заставили «Отправить» стать другим соответствующим действием. Я думал, что если не эксплицитно оформлен, метод Http по умолчанию Get? Разве это не устранит «Отправить» с использованием первых критериев? Кроме того, мой 'ComplexType' сильно отличается от' AnotherComplexType'. –

+0

'Send' и' Post' - это имена действий, которые могут быть взаимозаменяемы в соглашении. Кроме того, оба действия имеют один тип сложных параметров, которые исключаются при попытке сопоставления параметров. Я сделаю смелый раздел, который касается вашего комментария. – Nkosi

0

Вы можете попытаться украсить все ваши действия с атрибутом, как это, чтобы увидеть, если что-нибудь изменить

[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 и пост конфликтуют каким-то образом.

1

Если атрибут метода HTTP определен не определен, по умолчанию используется POST.Поэтому Send() также рассматривается как метод post, и исключение возникает, потому что найдено более одного действия.

Вы можете попробовать установить инструмент Debug Router, чтобы получить визуальное представление о том, как был выбран контроллер и действие. Вот a link

Смежные вопросы