Маршрутизация: текущий запрос действия […] неоднозначен для следующих методов действия

100

У меня есть View Browse.chtml, в котором пользователь может ввести поисковый запрос или оставить поле поиска пустым. При вводе поискового запроса я хочу направить страницу на, http://localhost:62019/Gallery/Browse/{Searchterm} а когда ничего не введено, я хочу направить браузер на http://localhost:62019/Gallery/Browse/Start/Here.

Когда я пытаюсь это сделать, я получаю сообщение об ошибке:

Текущий запрос действия «Обзор» для типа контроллера «GalleryController» неоднозначен для следующих методов действия: System.Web.Mvc.ActionResult Browse (System.String) для типа AutoApp_MVC.Controllers.GalleryController System.Web.Mvc.ActionResult Browse (Int32, System.String) для типа AutoApp_MVC.Controllers.GalleryController

Все, что я делаю с MVC, - впервые. Я не уверен, что еще попробовать на данном этапе.

public ActionResult Browse(string id)
{
    var summaries = /* search using id as search term */
    return View(summaries);
}

public ActionResult Browse(string name1, string name2)
{
    var summaries = /* default list when nothing entered */
    return View(summaries);
}

У меня также есть это в Global.asax.cs:

    routes.MapRoute(
         "StartBrowse",
         "Gallery/Browse/{s1}/{s2}",
         new
         {
             controller = "Gallery",
             action = "Browse",
             s1 = UrlParameter.Optional,
             s2 = UrlParameter.Optional
         });



    routes.MapRoute(
         "ActualBrowse",
         "Gallery/Browse/{searchterm}",
         new
         {
             controller = "Gallery",
             action = "Browse",
             searchterm=UrlParameter.Optional
         });
Дэйв
источник

Ответы:

161

У вас может быть не более 2 методов действий с одинаковым именем на контроллере, и для этого один должен быть [HttpPost], а другой должен быть [HttpGet].

Поскольку оба ваших метода - GET, вам следует либо переименовать один из методов действия, либо переместить его на другой контроллер.

Хотя ваши 2 метода Browse являются допустимыми перегрузками C #, селектор метода действия MVC не может определить, какой метод вызвать. Он попытается сопоставить маршрут с методом (или наоборот), и этот алгоритм не является строго типизированным.

Вы можете выполнить то, что хотите, используя настраиваемые маршруты, указывающие на различные методы действий:

... в Global.asax

routes.MapRoute( // this route must be declared first, before the one below it
     "StartBrowse",
     "Gallery/Browse/Start/Here",
     new
     {
         controller = "Gallery",
         action = "StartBrowse",
     });

routes.MapRoute(
     "ActualBrowse",
     "Gallery/Browse/{searchterm}",
     new
     {
         controller = "Gallery",
         action = "Browse",
         searchterm = UrlParameter.Optional
     });

... а в контроллере ...

public ActionResult Browse(string id)
{
    var summaries = /* search using id as search term */
    return View(summaries);
}

public ActionResult StartBrowse()
{
    var summaries = /* default list when nothing entered */
    return View(summaries);
}

Вы также можете сохранить одинаковые имена методов действий в контроллере , применив [ActionName]атрибут к одному из них, чтобы различать его. Используя тот же Global.asax, что и выше, ваш контроллер будет выглядеть следующим образом:

public ActionResult Browse(string id)
{
    var summaries = /* search using id as search term */
    return View(summaries);
}

[ActionName("StartBrowse")]
public ActionResult Browse()
{
    var summaries = /* default list when nothing entered */
    return View(summaries);
}
данлудвиг
источник
Итак, мне нужно будет создать новое представление в приведенном выше примере? Похоже, использование тега ActionName не помогает, поскольку я думаю, что он работает только для переименования всех методов действия (невозможно сохранить оба одновременно). Хорошо знать, как работает MVC. Спасибо.
Дэйв
6
Нет, создавать новые представления не нужно. Вы по-прежнему можете повторно использовать одно и то же представление для обоих действий. Просто передайте имя представления в качестве первого аргумента дляreturn View("Browse", summaries);
danludwig
Будет ли включена перегрузка в какой-нибудь будущий выпуск? Изменение маршрутов - это дополнительная работа, и при внесении изменений требуется дополнительное обслуживание.
Old Geezer
@OldGeezer, вероятно, нет, поскольку существует обходной путь (см. Выше) и потому, что перегруженные методы действий в контроллере обычно не являются хорошей идеей.
данлудвиг 01
4

Я не знаю, когда был задан вопрос, это решение было доступно, но вы можете использовать:

Request.QueryString["key"]

Итак, это должно работать нормально для вашей проблемы:

[HttpGet]
public ActionResult Browse()
{
    if( Request.QueryString["id"] != null )        
        var summaries = /* search using id as search term */
    else /*assuming you don't have any more option*/
        var summaries = /* default list when nothing entered */

    return View(summaries);
} 
Сайгын Догу
источник
2

Добавьте следующий код в RouteConfig.cs перед маршрутом по умолчанию

routes.MapMvcAttributeRoutes();

И добавьте атрибуты маршрута в контроллер, например:

    [Route("Cars/deteals/{id:int}")]
    public ContentResult deteals(int id)
    {
        return Content("<b>Cars ID Is " + id + "</b>");
    }

    [Route("Cars/deteals/{name}")]
    public  ContentResult deteals(string name)
    {
        return Content("<b>Car name Is " + name + "</b>");

    }
Омар Мохамед
источник
1

Я думаю, что здесь говорится о том, что вам не нужно неявно тестировать параметры строки запроса с помощью класса запроса.

MVC выполняет сопоставление за вас (если вы не внесли серьезных изменений в свои маршруты MVC).

Таким образом, путь ссылки действия

/umbraco/Surface/LoginSurface/Logout?DestinationUrl=/home/

будет автоматически доступен для вашего (поверхностного) контроллера с определенным параметром:

public ActionResult Logout(string DestinationUrl)

MVC делает свою работу.

Даррен-стрит
источник