ASP.NET MVC RouteValueDictionary和复杂对象

问题描述:

跨搜索结果页面保留表单发布(视图模型)结果的最佳方法是什么?ASP.NET MVC RouteValueDictionary和复杂对象

我有一个包含复选框的搜索表单。这种形式是建立使用视图模型像

public class SearchViewModel 
{ 
    public string Name { get; set; } 
    public string[] Colors { get; set; } 
} 

当这个视图模型被调回我用价值观来建立一个查询(使用EF)。结果转换为PagedList。

public class SearchController : Controller 
    { 
    public ActionResult Index() 
    { 
     //this displays the search form. 
     return View(); 
    } 

    public ActionResult Results(string game, SearchViewModel vm) 
    { 
     //this displays the results 
     ViewBag.SearchViewModel = vm; 
     var matches = _repository.AsQueryable() 
      .ColorOr(vm.Colors) 
      .WhereIf(vm.Name.IsNotEmpty(), x => x.Name.Contains(vm.Name.Trim())); 

      return View(matches.ToPagedList(1, 10)); 
    } 
} 

既然显示结果,我想使用Html.PagedListPager和RouteValueDictionary来创建分页。

@Html.PagedListPager((IPagedList)Model, page => Url.Action("Results", new RouteValueDictionary(ViewBag.SearchViewModel))) 

但是;创建的URL如下所示:

http://localhost:5139/search?Name=test&Colors=System.String[]&PageIndex=0 

Colors的值最终是类型而不是值。我希望的URL看起来更像:

http://localhost:5139/search?Name=test&Colors=[Blue,Pink,Yellow]&PageIndex=0 
  1. 什么能够保留整个搜索结果页面表单POST(视图模型)的结果,最好的方法是什么?
  2. RouteValueDictionary是否支持复杂对象?
  3. 我应该使用类似unbinder
  4. 我会更好使用ViewData或会话吗?
+0

哇。这是我确切的问题。 +1 – 2013-03-08 15:01:48

我已经做了这样的情况下,我觉得这有什么简单,但功能强大,被序列我视图模型对象,以JSON(你的情况SearchViewModel),使用类似与得到的JSON字符串NewtonSoft JSON.net然后,通过zlib.netZlib.DeflateStream类对字符串进行简单压缩(您也可以使用类似AES Rijndael的东西,但无疑会更慢,并且首先需要速度),然后将结果Base64字符串传递到您的QueryString中。

然后,当你准备再次使用它时(它实际上是一个视图状态),只需解压缩JSON字符串并将其从JSON反序列化到相应的.NET对象(再次在你的案例SearchViewModel)。

对于我来说,为我提供了一种享受,而且不会因为只有少数表单字段被序列化而导致无法管理的网址或任何真正可衡量的性能影响。

我将尽快详细介绍代码示例。

UPDATE:Code samples ...

这是我会做在您的特定方案:

Results(string, SearchViewModel)行动:

public ActionResult Results(string encryptedUrlViewModel, string game, SearchViewModel vm) 
{ 
    SearchViewModel searchUrlViewModel = null; 
    if (!string.IsNullOrEmpty(searchUrl)) { 
     // only first submission, no url view model set yet, so compress it and store.. 
     encryptedUrlViewModel = Convert.ToBase64String(
     DeflateStream.CompressString(JsonConvert.SerializeObject(vm))); 
     ViewBag.EncryptedUrlViewModel = encryptedUrlViewModel; 
    } 
    else { 
     var jsonUrlViewModel = DeflateStream.UncompressString(Convert.FromBase64String(encryptedUrlViewModel)); 
     searchUrlViewModel = JsonConvert.DeserializeObject(jsonUrlViewModel, typeof(SearchViewModel)) as SearchViewModel; 
     // at this point you should have a serialized 'SearchViewModel' object 
     // ready to use which you can then tweak your query below with. 
    } 
    var matches = _repository.AsQueryable() 
     .ColorOr(vm.Colors) 
     .WhereIf(vm.Name.IsNotEmpty(), x => x.Name.Contains(vm.Name.Trim())); 

    return View(matches.ToPagedList(1, 10)); 
} 

鉴于:

@Html.PagedListPager((IPagedList)Model, page => Url.Action("Results", new { encryptedUrlViewModel = ViewBag.EncryptedUrlViewModel })) 

的代码可能需要一些调整,未经检验在你的情况下,但它会是这样的,最好的运气:)

但是你应该真的考虑一下,如果你想在分页的URL中携带用户的请求,那么可以考虑为什么表格不是作为GET请求而不是作为POST请求。任何你特别想要的理由POST?我认为GET将正确地携带您的Colors阵列,但请确保您的视图模型设置正确。 See this Haacked article for model binding to lists

+0

只是要清楚。如上所述,最简单的解决方案是将表单方法从POST更改为GET。 – detroitpro 2011-12-22 04:19:44

+1

哈哈.... doh。哦,我的手制作了编码解决方案,以浪费。哦,以及:)你可能需要的东西就像它有一天.. =) – GONeale 2011-12-22 13:37:30

+0

进入这个有点晚,但面临类似的挑战。那么你会将整个搜索表单+结果列表包装在Html表单中以获得正确的模型绑定?如果整个视图处于窗体中,是搜索视图模型的分页部分,还是它是控制器操作的单独参数? – 2012-11-26 18:51:15

我有同样的问题,但与搜索参数。我们有一个颜色参数,它是搜索引擎使用的颜色名称列表。所以你可以勾选黑色和蓝色,结果包含黑色和蓝色产品。

我结束了使用Unbound

using Unbound; 
Unbinder u = new Unbinder(); 

@Url.Action("Index", new RouteValueDictionary(u.Unbind(SearchParams))) 

导致的链接,如:

/MyRoute?color[0]=black&color[1]=blue