我遇到过两种解决方案,一种是由我工作的人设计的,另一种是我的更优雅的解决方案!
第一种解决方案是为指定的路线指定延伸MVcRouteHandler
的类。此路由处理程序可以检查HttpContext
表单中的路由,读取表单数据,然后在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,然后定义自己的custome 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;
}
}
当它尝试解析给定URL的控制器上的正确操作方法时,MVC会调用此类。然后,我们申报操作方法如下:
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中非常酷的功能。
我希望这个答案对我以外的人有用。 :)