Я натолкнулся на два решения, одно из которых было разработано кем-то, с кем я работаю, а затем другое, более элегантное для меня!
Первое решение состояло в том, чтобы указать класс, который расширяет MVcRouteHandler
для указанного маршрута.Этот обработчик маршрута может проверить маршрут в форме HttpContext
, прочитать данные формы и затем обновить RouteData
в RequestContext.
MapRoute(routes,
"Book",
"{locale}/book",
new { controller = "Reservation", action = "Index" }).RouteHandler = new ReservationRouteHandler();
ReservationRouteHandler выглядит следующим образом:
public class ReservationRouteHandler: MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var request = requestContext.HttpContext.Request;
// First attempt to match one of the posted tab types
var action = ReservationNavigationHandler.GetActionFromPostData(request);
requestContext.RouteData.Values["action"] = action.ActionName;
requestContext.RouteData.Values["viewStage"] = action.ViewStage;
return base.GetHttpHandler(requestContext);
}
NavigationHandler фактически выполняет работу по поиску данных формы, но вы поняли идею.
Это решение работает, однако, оно выглядит немного неуклюжим и, глядя на класс контроллера, вы никогда не узнаетеэто происходило, и я бы не понял, почему en-gb / book будет указывать на разные методы, не говоря уже о том, что это не так уж многократно.
Лучшее решение состоит в том, чтобы перегружать методы на контроллере, т. Е. В этом случае они все называются book, а затем определять ваш собственный обычный ActionMethodSelectorAttribute.Это то, из чего вытекает атрибут HttpPost.
public class FormPostFilterAttribute : ActionMethodSelectorAttribute
{
private readonly string _elementId;
private readonly string _requiredValue;
public FormPostFilterAttribute(string elementId, string requiredValue)
{
_elementId = elementId;
_requiredValue = requiredValue;
}
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (string.IsNullOrEmpty(controllerContext.HttpContext.Request.Form[_elementId]))
{
return false;
}
if (controllerContext.HttpContext.Request.Form[_elementId] != _requiredValue)
{
return false;
}
return true;
}
}
MVC вызывает этот класс, когда пытается разрешить правильный метод действия на контроллере с учетом URL-адреса.Затем мы объявляем методы действия следующим образом:
public ActionResult Book(HotelSummaryPostData hotelSummary)
{
return View("CustomerDetails");
}
[FormFieldFilter("stepID", "1")]
public ActionResult Book(YourDetailsPostData yourDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[FormFieldFilter("stepID", "2")]
public ActionResult Book(RoomDetailsPostData roomDetails, RequestedViewPostData requestedView)
{
return View(requestedView.RequestedView);
}
[HttpGet]
public ActionResult Book()
{
return View();
}
Нам нужно определить скрытое поле stepID на разных страницах, чтобы при отправке форм на этих страницах обратно на общий URL-адрес атрибуты SelectorAttributes правильно определяли, какое действиеметод для вызова.Я был удивлен, что он правильно выбирает метод действия, когда метод с одинаковым именем существует без набора атрибутов, но также рад.
Я не смотрел, можете ли вы сложить эти селекторы методов, я думаю, что вы можетехотя это сделало бы эту чертовски классную функцию в MVC.
Я надеюсь, что этот ответ пригодится кому-то, кроме меня.:)