我们有一个PHP应用程序,我们正在转换为MVC。目标是使应用程序在URL和HTML方面保持相同(SEO等等+ PHP站点仍在处理中)。我们有一个由3个视图组成的预订流程,在当前的PHP站点中,所有这些视图都回发到相同的URL,发送隐藏字段以区分预订过程中的哪个页面/步骤被发回(页面之间的数据存储在查询建立的状态下)。
要在MVC中复制它,我们可以使用一个单独的操作方法,所有3个页面都会发布,只有一个绑定器只根据发布的页面填充模型的一部分,并且控制器会查看模型并决定预订过程中的下一个阶段。或者如果这可能(这是我的问题),设置一个可以读取POST参数的路由,并根据POST参数的值,路由到不同的操作方法。
据我所知,MVC路由中没有对此的支持,因为它代表(但我希望在这方面是错误的),那么我需要在哪里考虑扩展MVC才能支持这一点? (我认为多种动作方法更加清晰。)
非常感谢您的帮助。
答案 0 :(得分:2)
我遇到了两个解决方案,一个由我工作的人设计,另一个是我更优雅的解决方案!
第一个解决方案是指定一个扩展MVcRouteHandler
指定路由的类。此路由处理程序可以检查HttpContext
的Form中的路径,读取Form数据,然后更新RequestContext中的RouteData
。
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中使用这个非常酷的功能。
我希望这个答案对我以外的人有用。 :)