如何将POST请求重定向到维护MVC中的模型值的URL

时间:2011-07-25 19:57:52

标签: asp.net-mvc model-view-controller asp.net-mvc-2

我有一个相当标准的排序/过滤器/页面搜索表单,但需要控制url的格式。 sort / filter / page参数应该都是url的一部分,例如,地址可以通过电子邮件发送给某人。

添加另一个过滤器参数时,会发出POST请求。我的控制器方法如下所示:

[HttpPost]
public ActionResult Search(string filterField,
                           Operator filterOperator, 
                           string filterValue, 
                           PeopleGroupSearchModel model);

从查询字符串参数填充PeopleGroupSearchModelfilter*参数来自已发布的表单值。

我想解析提供的过滤器值,然后将过滤器添加到名为Filters的模型中的集合中。然后,获取更新的模型并将其转换为相应的URL并将其作为响应传递给用户。

因此,例如,如果他们在此页面上:

PeopleGroup/Search?page=4&sort=Country

...和POST:

  • filterField = PeopleGroupName
  • filterOperator =等于
  • filterValue = Zulu

...完成所有处理后,浏览器中的地址应为:

PeopleGroup/Search?page=4&sort=Country&PeopleGroupName=Zulu&PeopleGroupName_op=Equals

所以,或多或少我要做的事情:

[HttpGet]
public ActionResult Search(PeopleGroupSearchModel model)
{
    PeopleGroupData.Search(model);
    ViewData.Model = model;
    return View();
}

[HttpPost]
public ActionResult Search(string filterField,
                           Operator filterOperator,
                           string filterValue,
                           PeopleGroupSearchModel model)
{
    PeopleGroupFilter filter = ParseFilter(filterField, 
                                           filterOperator, 
                                           filterValue);
    model.Filters.Add(filter);
    return RedirectToAction("Search", ???);
}

非常对MVC来说是新的,所以如果我这样做完全错误的话,请告诉我!

3 个答案:

答案 0 :(得分:11)

在ASP.NET MVC中有几种可能性来实现Redirect-After-Post模式(这就是你在此之后,这是一个非常好的模式IMHO):

  1. 使用TempData。在POST操作中,将模型存储在TempData内并重定向:

    TempData["model"] = model;
    return RedirectToAction("Search");
    

    然后在搜索操作内部检查TempData存在以获取模型:

    PeopleGroupSearchModel model = TempData["model"] as PeopleGroupSearchModel;
    

    这种方法的缺点是TempData仅针对单个重定向持久化,这意味着如果用户在搜索GET操作时遇到F5,则会被搞砸。这可以通过使用Session来缓解。但当然Session引入了另一个可扩展性问题。所以我不喜欢这种做法。

  2. 传递请求中的所有属性:

    return RedirectToAction("Search", new {
        prop1 = model.Prop1,
        prop2 = model.Prop2, 
        ....
    });
    

    现在,当重定向到Search GET操作时,默认模型绑定器将能够重建模型。这种方法的一个明显缺点是,如果您的模型具有许多属性,甚至更复杂类型的性能,这很快就会成为一种麻烦的解决方案。您可以使用某些文本格式(例如JSON)作为查询字符串参数来序列化模型。当然,查询字符串参数在不同的浏览器之间是有限的,所以这也可以是禁忌。

  3. 将模型保留在某些数据存储中并检索唯一ID,以便以后可以从此存储中检索它:

    int id = Persist(model);
    return RedirectToAction("Search", new { id = id });
    

    然后在GET操作中使用id从这个相同的持久性存储中检索模型。我喜欢这种方法并且大多数时候都在使用它。如果坚持上述数据存储区是昂贵的,您可以使用缓存。

答案 1 :(得分:2)

您可以将需要保留的值放入ControllerContext.RouteData.Values

    public ActionResult TestRedirect()
    {
        RouteValueDictionary routeValues = ControllerContext.RouteData.Values;
        routeValues.Add("Key1","value1");
        routeValues.Add("Key2","value2");

        return RedirectToAction("TargetRedirect", routeValues);
    }

如果你需要更通用的东西,你可以遍历postet表单元素。

修改

这看起来像是评分最高的答案:How do you persist querystring values in asp.net mvc?

答案 2 :(得分:2)

这可能违反了MVC原则,但是一旦我停止对框架的斗争,只是想到我在HTTP-land中尝试做什么,这个简单的解决方案对我有用:

[HttpPost]
public ActionResult Search(PeopleGroupColumn filterField,
                           Operator filterOperator,
                           string filterValue)
{
    var collection =
        HttpUtility.ParseQueryString(Request.QueryString.ToString());
    collection.Set(filterField.ToString(), filterValue);
    collection.Set(filterField.ToString() + "_op", filterOperator.ToString());
    return new RedirectResult(
        Request.Url.AbsolutePath + "?" + collection.ToString());
}