Можете ли вы перегрузить методы контроллера в ASP.NET MVC?

Мне интересно узнать, можете ли вы перегрузить методы контроллера в ASP.NET MVC. Всякий раз, когда я пытаюсь, я получаю ошибку ниже. Эти два метода принимают разные аргументы. Это что-то, что нельзя сделать?

Текущий запрос действия "MyMethod" на тип контроллера "MyController" неоднозначен между следующими методами:

Ответ 1

Вы можете использовать атрибут, если хотите, чтобы ваш код перегружал.

[ActionName("MyOverloadedName")]

Но вам придется использовать другое имя действия для того же метода http (как говорили другие). Так что это просто семантика в этот момент. Вы предпочитаете иметь имя в своем коде или вашем атрибуте?

У Фила есть статья, связанная с этим: http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx

Ответ 2

Да. Я смог сделать это, установив атрибут HttpGet/HttpPost (или эквивалентный AcceptVerbs) для каждого метода контроллера для чего-то другого, т.е. HttpGet или HttpPost, но не для обоих. Таким образом, он может указывать на основе типа запроса, какой метод использовать.

[HttpGet]
public ActionResult Show()
{
   ...
}

[HttpPost]
public ActionResult Show( string userName )
{
   ...
}

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

Ответ 3

Здесь что-то еще вы можете сделать... вы хотите метод, который может иметь параметр, а не.

Почему бы не попробовать это...

public ActionResult Show( string username = null )
{
   ...
}

Это сработало для меня... и в этом методе вы можете проверить, есть ли у вас входящий параметр.


Обновлено, чтобы удалить недействительный синтаксис NULL для строки и использовать значение параметра по умолчанию.

Ответ 4

Нет, нет и нет. Идите и попробуйте код контроллера ниже, где мы загрузили "LoadCustomer" .

public class CustomerController : Controller
    {
        //
        // GET: /Customer/

        public ActionResult LoadCustomer()
        {
            return Content("LoadCustomer");
        }
        public ActionResult LoadCustomer(string str)
        {
            return Content("LoadCustomer with a string");
        }
    }

Если вы попытаетесь вызвать действие "LoadCustomer" , вы получите ошибку, как показано на рисунке ниже.

enter image description here

Полиморфизм является частью программирования на С#, а HTTP - протоколом. HTTP не понимает полиморфизм. HTTP работает над концепцией или URL-адресом, а URL-адрес может иметь только уникальное имя. Таким образом, HTTP не реализует полиморфизм.

Чтобы исправить то же самое, нам нужно использовать атрибут "ActionName".

public class CustomerController : Controller
    {
        //
        // GET: /Customer/

        public ActionResult LoadCustomer()
        {
            return Content("LoadCustomer");
        }

        [ActionName("LoadCustomerbyName")]
        public ActionResult LoadCustomer(string str)
        {
            return Content("LoadCustomer with a string");
        }
    }

Итак, теперь, если вы вызываете URL-адрес "Клиент/LoadCustomer", вызывается действие "LoadCustomer" и со структурой URL "Customer/LoadCustomerByName" вызывается "LoadCustomer (string str)".

enter image description here

enter image description here

Вышеупомянутый ответ, который я взял из этой статьи кодекса → Перегрузка действия MVC

Ответ 5

Чтобы преодолеть эту проблему, вы можете написать ActionMethodSelectorAttribute, который анализирует MethodInfo для каждого действия и сравнивает его с опубликованными значениями формы, а затем отклоняет любой метод, для которого значения формы не совпадают (исключая имя кнопки, конечно).

Вот пример: - http://blog.abodit.com/2010/02/asp-net-mvc-ambiguous-match/

НО, это не очень хорошая идея.

Ответ 6

Насколько я знаю, вы можете использовать один и тот же метод при использовании разных методов http.

то есть.

[AcceptVerbs("GET")]
public ActionResult MyAction()
{

}

[AcceptVerbs("POST")]
public ActionResult MyAction(FormResult fm)
{

}

Ответ 7

Я достиг этого с помощью Маршрутизация атрибутов в MVC5. По общему признанию, я новичок в MVC из десятилетия веб-разработки с использованием WebForms, но для меня это работало. В отличие от принятого ответа, это позволяет отображать все перегруженные действия одним и тем же файлом вида.

Сначала включите маршрутизацию атрибутов в App_Start/RouteConfig.cs.

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapMvcAttributeRoutes();

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );            
    }
}

Опционально украсьте свой класс контроллера префиксом маршрута по умолчанию.

[RoutePrefix("Returns")]
public class ReturnsController : BaseController
{
    //.......

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

[HttpGet]
// Returns
public ActionResult Index()
{
    //.....
}

[HttpGet]
[Route("View")]
// Returns/View
public ActionResult View()
{
    // I wouldn't really do this but it proves the concept.
    int id = 7026;
    return View(id);
}

[HttpGet]
[Route("View/{id:int}")]
// Returns/View/7003
public ActionResult View(int id)
{
    //.....
}

[HttpGet]
[Route("View/{id:Guid}")]
// Returns/View/99300046-0ba4-47db-81bf-ba6e3ac3cf01
public ActionResult View(Guid id)
{
    //.....
}

Надеюсь, что это поможет и не ведет кого-то по неверному пути.: -)

Ответ 8

Вы можете использовать один ActionResult для работы как с Post, так и Get:

public ActionResult Example() {
   if (Request.HttpMethod.ToUpperInvariant() == "GET") {
    // GET
   }
   else if (Request.HttpMethod.ToUpperInvariant() == "POST") {
     // Post  
   }
}

Полезно, если ваши методы Get и Post имеют соответствующие подписи.

Ответ 9

Я только что наткнулся на этот вопрос, и, хотя он довольно старый, он все еще очень уместен. Как ни странно, один правильный комментарий в этой теме был опубликован самонадеянным новичком в MVC, когда он написал сообщение. Даже документы ASP.NET не совсем корректны. У меня большой проект, и я успешно перегружаю методы действий.

Если понимать маршрутизацию, помимо простого шаблона маршрута {controller}/{action}/{id} по умолчанию, может быть очевидно, что действия контроллера могут быть сопоставлены с использованием любого уникального шаблона. Кто-то здесь говорил о полиморфизме и сказал: "HTTP не понимает полиморфизм", но маршрутизация не имеет ничего общего с HTTP. Это простой механизм для сопоставления строк.

Лучший способ сделать эту работу - использовать атрибуты маршрутизации, например:

[RoutePrefix("cars/{country:length(3)}")]
public class CarHireController
{
    [Route("{location}/{page:int=1}", Name = "CarHireLocation")]
    public ActionResult Index(string country, string location, int page)
    {
        return Index(country, location, null, page);
    }

    [Route("{location}/{subLocation}/{page:int=1}", Name = "CarHireSubLocation")]
    public ActionResult Index(string country, string location, string subLocation, int page)
    {
        //The main work goes here
    }
}

Эти действия позаботятся об URL-адресах, таких как /cars/usa/new-york и /cars/usa/texas/dallas, которые будут отображаться соответственно для первого и второго действий индекса.

Изучив этот пример контроллера, очевидно, что он выходит за рамки шаблона маршрута по умолчанию, упомянутого выше. По умолчанию работает хорошо, если ваша структура URL точно соответствует соглашениям об именах кода, но это не всегда так. Код должен описывать домен, но URL-адреса часто должны идти дальше, потому что их контент должен основываться на других критериях, таких как требования к SEO.

Преимущество шаблона маршрутизации по умолчанию заключается в том, что он автоматически создает уникальные маршруты. Это обеспечивается компилятором, поскольку URL-адреса будут соответствовать уникальным типам контроллеров и членам. Прокрутка собственных шаблонов маршрутов потребует тщательной мысли, чтобы обеспечить уникальность и работу.

Важное примечание Единственный недостаток заключается в том, что использование маршрутизации для генерации URL-адресов для перегруженных действий не работает, когда оно основано на имени действия, например, при использовании UrlHelper.Action. Но он работает, если вы используете именованные маршруты, например UrlHelper.RouteUrl. И использование названных маршрутов, по мнению уважаемых источников, способ как-то идти (http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/).

Удачи!

Ответ 10

Вы можете использовать [ActionName ("NewActionName")] для использования того же метода с другим именем:

public class HomeController : Controller
{
    public ActionResult GetEmpName()
    {
        return Content("This is the test Message");
    }

    [ActionName("GetEmpWithCode")]
    public ActionResult GetEmpName(string EmpCode)
    {
        return Content("This is the test Messagewith Overloaded");
    }
}

Ответ 11

Мне нужна перегрузка для:

public ActionResult Index(string i);
public ActionResult Index(int groupId, int itemId);

Достаточно немного аргументов, в которых я это сделал:

public ActionResult Index(string i, int? groupId, int? itemId)
{
    if (!string.IsNullOrWhitespace(i))
    {
        // parse i for the id
    }
    else if (groupId.HasValue && itemId.HasValue)
    {
        // use groupId and itemId for the id
    }
}

Это не идеальное решение, особенно если у вас много аргументов, но он работает хорошо для меня.

Ответ 12

Я тоже сталкивался с такой же проблемой в своем приложении. Без Modifiyig любой информации о методе я предоставил [ActionName ( "SomeMeaningfulName" )] в Action Action. проблема решена

[ActionName("_EmployeeDetailsByModel")]
        public PartialViewResult _EmployeeDetails(Employee model)
        {
            // Some Operation                
                return PartialView(model);
            }
        }

[ActionName("_EmployeeDetailsByModelWithPagination")]
        public PartialViewResult _EmployeeDetails(Employee model,int Page,int PageSize)
        {

                // Some Operation
                return PartialView(model);

        }

Ответ 13

Создайте базовый метод как виртуальный

public virtual ActionResult Index()

Создайте переопределенный метод как переопределяющий

public override ActionResult Index()

Изменить: это, очевидно, применимо только в том случае, если метод переопределения находится в производном классе, который, как представляется, не был намерением OP.

Ответ 15

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

Если вы не хотите использовать разные глаголы (например, атрибуты [HttpGet] и [HttpPost]), чтобы различать перегруженные методы (которые будут работать) или изменять маршрутизацию, то остается то, что вы можете либо предоставить другой метод с другим именем или вы можете отправить внутри существующего метода. Вот как я это сделал:

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

Чтобы решить эту проблему, я сделал следующее:

  • Изменено 2 перегруженных метода действий от общего доступа к частному
  • Создан один новый общедоступный метод, содержащий "только" 2 строковых параметра. Это действовало как диспетчер, то есть:

    public ActionResult DoSomething(string param1, string param2)
    {
        if (string.IsNullOrEmpty(param2))
        {
            return DoSomething(ProductName: param1);
        }
        else
        {
            int oldId = int.Parse(param1);
            return DoSomething(OldParam: param1, OldId: oldId);
        }
    }
    
    
    private ActionResult DoSomething(string OldParam, int OldId)
    {
        // some code here
        return Json(result);
    }
    
    
    private ActionResult DoSomething(string ProductName)
    {
        // some code here
        return Json(result);
    }
    

Конечно, это взлом, и его нужно реорганизовать позже. Но на данный момент это сработало для меня.

Вы также можете создать диспетчера, например:

public ActionResult DoSomething(string action, string param1, string param2)
{
    switch (action)
    {
        case "update":
            return UpdateAction(param1, param2);
        case "remove":
            return DeleteAction(param1);
    }
}

Вы можете видеть, что UpdateAction требует 2 параметра, а DeleteAction - только один.

Ответ 16

Извините за задержку. У меня была такая же проблема, и я нашел ссылку с хорошими ответами, может это поможет новым парням

Все кредиты для сайта BinaryIntellect и авторов

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

Итак, зависит от ваших требований и вашей ситуации.

Как бы то ни было, перейдите по ссылке:

Ссылка: http://www.binaryintellect.net/articles/8f9d9a8f-7abf-4df6-be8a-9895882ab562.aspx

Ответ 17

Если это попытка использовать одно действие GET для нескольких представлений, которые POST выполняет несколькими действиями с разными моделями, попробуйте добавить действие GET для каждого действия POST, которое перенаправляет на первый GET, чтобы предотвратить обновление 404.

Длинный снимок, но общий сценарий.