Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Model view controller 基于POST参数的MVC路由_Model View Controller_Asp.net Mvc Routing - Fatal编程技术网

Model view controller 基于POST参数的MVC路由

Model view controller 基于POST参数的MVC路由,model-view-controller,asp.net-mvc-routing,Model View Controller,Asp.net Mvc Routing,我们有一个PHP应用程序,正在转换为MVC。目标是让应用程序在URL和HTML方面保持一致(SEO和类似的+PHP站点仍在开发中)。我们有一个由3个视图组成的预订流程,在当前的PHP站点中,所有这些视图都发回相同的URL,并发送一个隐藏字段来区分预订流程中的哪个页面/步骤被发回(页面之间的数据在查询建立时以状态存储) 为了在MVC中复制这一点,我们可以使用一个单一的操作方法,所有3个页面都发布到该方法中,使用一个活页夹,该活页夹仅填充模型的一部分,具体取决于从哪个页面发布,控制器查看模型并决定预

我们有一个PHP应用程序,正在转换为MVC。目标是让应用程序在URL和HTML方面保持一致(SEO和类似的+PHP站点仍在开发中)。我们有一个由3个视图组成的预订流程,在当前的PHP站点中,所有这些视图都发回相同的URL,并发送一个隐藏字段来区分预订流程中的哪个页面/步骤被发回(页面之间的数据在查询建立时以状态存储)

为了在MVC中复制这一点,我们可以使用一个单一的操作方法,所有3个页面都发布到该方法中,使用一个活页夹,该活页夹仅填充模型的一部分,具体取决于从哪个页面发布,控制器查看模型并决定预订过程中的下一个阶段。或者,如果这是可能的(这是我的问题),设置一个可以读取POST参数的路由,并根据POST参数的值,路由到不同的操作方法

据我所知,MVC路由目前不支持这一点(但我希望在这一点上是错误的),那么为了支持这一点,我需要在哪里考虑扩展MVC呢?(我认为多种行动方法在某种程度上更干净)


非常感谢您的帮助。

我想出了两个解决方案,一个是我的同事设计的,另一个是我自己设计的更优雅的解决方案

第一个解决方案是为指定的路由指定一个扩展
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 Action MethodSelectorAttribute。这就是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中成为一个非常酷的特性


我希望这个答案对我以外的人有用

我想出了两个解决方案,一个是我的同事设计的,另一个是我自己设计的更优雅的解决方案

第一个解决方案是为指定的路由指定一个扩展
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 Action MethodSelectorAttribute。这就是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中成为一个非常酷的特性

我希望这个答案对我以外的人有用