Можете ли вы перегрузить методы контроллера в ASP.NET MVC?
Мне любопытно посмотреть, если вы можете перегрузить методы контроллера в ASP.NET MVC. Всякий раз, когда я пытаюсь, я получаю ошибку ниже. Эти два метода принимают различные аргументы. Это то, что не может быть сделано?
текущий запрос на действие "MyMethod" на контроллере типа "MyController" неоднозначен между следующими методами действия:
16 ответов:
вы можете использовать атрибут, если вы хотите, чтобы ваш код, чтобы не перегружать.
[ActionName("MyOverloadedName")]но вам придется использовать другое имя действия для того же метода http (как говорили другие). Так что это просто семантика в тот момент. Вы бы предпочли иметь имя в своем коде или свой атрибут?
у Фила есть статья, связанная с этим:http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx
да. Я был в состоянии сделать это, установив
HttpGet/HttpPost(или эквивалентAcceptVerbsатрибут) для каждого метода контроллера к чему-то отличному, т. е.HttpGetилиHttpPost, но не оба. Таким образом, он может сказать, основываясь на типе запроса, какой метод использовать.[HttpGet] public ActionResult Show() { ... } [HttpPost] public ActionResult Show( string userName ) { ... }одно из моих предложений заключается в том, что для такого случая было бы иметь частную реализацию, на которую опираются оба ваших метода публичных действий, чтобы избежать дублирования кода.
вот еще что вы могли бы сделать... вы хотите метод, который может иметь параметр и нет.
почему бы не попробовать это...
public ActionResult Show( string username = null ) { ... }это сработало для меня... и в этом одном методе вы можете проверить, есть ли у вас входящий параметр.
Обновлено, чтобы удалить недопустимый синтаксис nullable в строке и использовать значение параметра по умолчанию.
нет,нет и нет. Идите и попробуйте код контроллера ниже, где у нас есть" 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(string 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, начиная с десятилетия веб-разработки с использованием веб-форм, но для меня сработало следующее. В отличие от принятого ответа, это позволяет отображать все перегруженные действия одним и тем же файлом представления.
сначала включите маршрутизацию атрибутов в App_Start / RouteConfig.цезий.
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.Действие. Но это работает, если вы используете именованные маршруты, например, UrlHelper.RouteUrl. И использование именованных маршрутов-это, согласно хорошо уважаемым источникам, путь в любом случае (http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/).
удачи!
мне нужна была перегрузка для:
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 ("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"); } }
я столкнулся с той же проблемой в моем приложении тоже. Без Modifiyig любой информации о методе, я предоставил [ActionName ("SomeMeaningfulName")] на голову действия. проблема решена
[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()создать переопределенный метод как override
public override ActionResult Index()Edit: это, очевидно, применяется только в том случае, если метод override находится в производном классе, который, как представляется, не был намерением OP.
Мне нравится этот ответ, опубликованный в другом потоке
Это в основном используется, если вы наследуете от другого контроллера и хотите переопределить аккцию от базового контроллера
ASP.NET MVC-переопределение действия с различными параметрами
для каждого метода контроллера разрешена только одна общедоступная подпись. Если вы попытаетесь перегрузить его, он будет компилироваться, но вы получаете ошибку времени выполнения, которую вы испытали.
если вы не хотите использовать разные глаголы (например,
[HttpGet]и[HttpPost]атрибуты) для дифференциации перегруженных методов (которые будут работать) или изменения маршрутизации, то остается то, что вы можете либо предоставить другой метод с другим именем, либо вы можете отправить внутри существующего метод. Вот как я это сделал:однажды я попал в ситуацию, когда мне пришлось поддерживать обратную совместимость. Первоначальный метод ожидал два параметра, но новый имел только один. Перегрузка так, как я ожидал, не сработала, потому что MVC больше не нашел точку входа.
чтобы решить эту проблему, я сделал следующее:
- изменил 2 перегруженных метода действий с public на private
создан один новый открытый метод который содержал" только " 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 для нескольких представлений, которые публикуют несколько действий с разными моделями, попробуйте добавить действие GET для каждого действия POST, которое перенаправляет на первое GET, чтобы предотвратить 404 при обновлении.
длинный выстрел, но общий сценарий.



Comments