【问题标题】:Persisting Dropdown information when ModelState is not valid当 ModelState 无效时保留下拉信息
【发布时间】:2014-03-14 13:32:02
【问题描述】:

我的 DropDownLists 有一些问题,因为当我发布信息并且我的模型无效时,它会返回“空”到页面,触发与 this question 完全相同的错误。

我已经使用了那里提出的解决方案,它解决了我的问题。无论如何,我想避免每次我的 ModelState 无效时都查询数据库,我采用了这种方法。我想知道它是否有效,或者现在是否有更好的方法,考虑到我现在使用的是 MVC 5 而不是 MVC2(这是来自 question 的 MVC 版本),也许他们添加了一些新的东西解决这个问题。

我所做的是在我的模型无效时使用 TempData 来保存信息。

public class ViewModel
{
    [DisplayName("Project")]
    public int ProjectID { get; set; }
    public List<SelectListItem> Projects { get; set; }

    //Other fields
}

现在我的 Create() 操作(填充项目)

[HttpGet]
public ActionResult Create()
{
    ViewModel vmodel = new ViewModel();
    vmodel.Projects = db.GetProjects(User.Identity.Name).Select(x => new SelectListItem { Text = x.Description, Value = x.Id }).ToList();
    TempData["Projects"] = vmodel.Projects;

    return View(vmodel);
}

我的帖子会是这样的:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ViewModel vmodel)
{
    //Clear TempData (in theory will clear my tempdata when read, so if this controller redirects to another action my tempdata will be clear)
    List<SelectListItem> projects = (TempData["Projects"] as List<SelectListItem>);

    if (ModelState.IsValid)
    {
        //...
    }

    //If it got here it's going back to the screen.
    //Repopulate the TempData (allowing it to exist one more trip)
    TempData["Projects"] = projects;
    vmodel.Projects = projects

    return View(atendimento);
}

这种方法好用吗?有没有更好的方法来实现这一点,而无需每次都查询数据库?

非常感谢!

【问题讨论】:

  • 你用这种方法测试过 TempData 吗?我虽然 TempData 仅通过相同的 HTTP 请求存活,这意味着它应该在页面加载时消失,并且在回发时不可用。
  • 是的,我在发帖之前就这样做了。它之所以有效,是因为我正在访问 ViewModel 来填充 DropDownList 而不是 TempData。这样,它只能在控制器上被访问。如果控制器中出现错误,我只需重新填充 TempData,使其再次访问屏幕并返回(因为它没有在那里读取)

标签: c# asp.net-mvc validation


【解决方案1】:

您根本不需要使用TempData,因为您的视图模型中有一个属性来保存下拉项。

public ActionResult Create()
{
    ViewModel vmodel = new ViewModel();
    vmodel.Projects = GetProjects(); 
    return View(vmodel);
}
private List<SelectListItem> GetProjects()
{
     return db.GetProjects(User.Identity.Name)
                 .Select(x => new SelectListItem { Text = x.Description,
                                                   Value = x.Id }).ToList();   
}

在视图中

@Html.DropDownListFor(s=>s.ProjectID,Model.Projects)

并且在您的 HttpPost 操作中,如果 ModelState 无效,请重新加载 Projects 集合(因为 http 是无状态的

if(ModelState.IsValid)
{
  // to do :Save and redirect
}
model.Projects = GetProjects(); 
return View(model);

如果您太担心性能,您可以缓存Projects,这样就不需要每次都访问数据库。

【讨论】:

  • 我正在使用完全一样的视图,我想避免的是每次模型从数据库中不正确时重新加载项目,特别是因为我的信息是用户敏感的并且它是相当大的数据库。
  • @RafaelMerlin 我提到你可以根据需要缓存它。检查这篇文章stevescodingblog.co.uk/net4-caching-with-mvc
  • 这个例子展示了标准的最佳实践用法。除非在您的具体示例中数据库存在性能问题,否则我会坚持使用这种模型。问题是,用户多久会错误地填写表格。缓存有它自己的性能开销(尽管它在网络服务器端)。
  • 记住TempData 使用Session 作为后台存储。想象一下,您有 1000 多个客户端在执行此操作,并且您正在使用会话数据来加热您的服务器!
  • 非常感谢!我也很喜欢你在这里添加的文章。
【解决方案2】:

就个人而言,我不会担心每次都为这种操作查询数据库。

如果添加/删除项目怎么办?这可能是保存失败(已删除选定项目)的原因,用户永远不会意识到这一点。

我通常会编写一个方法来填充我的所有视图模型的SelectListItems,然后在我的Get 和我的Post 中使用它(如果验证失败)。

【讨论】:

  • 我用这个只是一个例子,事实上我是在调用一个非常繁重的存储过程来获得我需要的信息。我不只处理项目,我的屏幕上至少有 10 个不同的下拉菜单,其中大多数每个都有不到 20 个项目,所以我认为最好保留这些信息而不是从 Db 再次获取它.
  • 用户在填写表单时选择的其中一项是否可能已被删除?根据您实施验证的方式,这可能会被视为验证错误。如果这种情况很可能发生,那么保留相同的项目将是错误的。
猜你喜欢
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
  • 2013-09-27
  • 1970-01-01
  • 2019-08-23
  • 1970-01-01
相关资源
最近更新 更多