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

StackOverflow https://stackoverflow.com/questions/436866

  •  22-07-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

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

[ActionName("MyOverloadedName")]

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

У Фила есть статья, связанная с этим:

Другие советы

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

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

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

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

Вот еще что можно сделать...вам нужен метод, который может иметь параметр, а не иметь его.

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

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

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


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

Нет, Нет и Нет. Перейдите и попробуйте приведенный ниже код контроллера, где у нас есть " 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 " действие, вы получите ошибку, как показано на рисунке ниже.

введите описание изображения здесь

Полиморфизм является частью программирования на C #, а 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-адресу " Customer / LoadCustomer " " LoadCustomer " будет вызвано действие со структурой URL " Customer / LoadCustomerByName " " LoadCustomer (строка str) " будет вызван.

введите описание изображения здесь

введите описание изображения здесь

Приведенный выше ответ я взял из этой статьи codeproject - > Перегрузка действия MVC

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

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

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

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

то есть

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

}

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

}

Я добился этого с помощью Маршрутизация атрибутов в 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)
{
    //.....
}

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

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

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

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

Я только что натолкнулся на этот вопрос, и хотя он довольно старый, он все еще очень актуален. По иронии судьбы, один правильный комментарий в этой теме был опубликован новичком в 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/ ).

Удачи!

Вы можете использовать [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");
    }
}

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

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

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

Я столкнулся с той же проблемой в моем приложении. Без изменения какой-либо информации о методе я предоставил [ActionName (" SomeMeaningfulName ")] в заголовке 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);

        }

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

public virtual ActionResult Index()

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

public override ActionResult Index()

Редактировать. Очевидно, что это применимо только в том случае, если метод переопределения находится в производном классе, который, как представляется, не являлся целью OP.

Мне нравится этот ответ, опубликованный в другой теме

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

ASP.NET MVC - переопределение действия с различными параметрами

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

Если вы не хотите использовать разные глаголы (например, атрибуты [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 - один.

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

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

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top