我遇到過兩種解決方案,一種是由我工作的人設計的,另一種是我的更優雅的解決方案!
第一種解決方案是爲指定的路線指定延伸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中非常酷的功能。
我希望這個答案對我以外的人有用。 :)