ASP.net MVC - 如何在各种视图中保留模型

Posted

技术标签:

【中文标题】ASP.net MVC - 如何在各种视图中保留模型【英文标题】:ASP.net MVC - How to persist model over various views 【发布时间】:2010-12-13 11:19:25 【问题描述】:

情况:在一些用 asp.net 编写的项目管理软件中,我有一个创建项目页面(工作正常)。我需要添加将任务从模板列表添加到此项目预创建的能力,但可用任务列表取决于创建表单中的某些值。

我的抽象解决方案是这样的:

我有一个“创建”视图和一个“添加任务”视图 - 两者都强类型化到控制器中定义的复合 viewModel 我的 Create 方法检查使用哪个按钮来调用它 - 如果 按钮是“添加任务”,然后它呈现 AddTasks 视图,从创建视图传递模型,再次在同一个控制器中。 AddTasks 视图使用两个按钮之一发布到 Create 视图,一个加载视图,另一个导致实际的数据库保存。

我的问题是这样的:

不同的视图使用相同模型的不同属性,但是在它们之间传递这个模型时,数据被重置(在任何情况下都重新加载或保存)。 我猜这是由于数据的自动绑定而发生的 - 尽管我认为表单上不存在的字段不会覆盖传递下来的现有模型数据。 目前控制器中几乎没有任何代码来操作模型 - 在这些情况下,它只在视图之间传递。

这是控制器代码:

    // POST: /Project/Create/<viewModel>
    [Authorize, AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude = "Id,id")] ProjectViewModel model)
    
        if (model.SubmitValue == "Create")
        
            try
            
                model.Project.Id = Guid.NewGuid();
                model.Save(this.User.Identity.Name);
                return this.RedirectToAction("Details", new id = model.Project.Id);
            
            catch (Exception e)
            
                this.ModelState.AddModelError(e.ToString(), e.ToString());
            
            return View(model);
        

        if(model.SubmitValue == "AddTasks")
        
            return this.View("AddTasks",model);
        

        return this.View(model);

    


    //POST: /Project/AddTasks/ + model
    [Authorize, AcceptVerbs(HttpVerbs.Post)]
    public ActionResult AddTasks([Bind(Include = SelectedCarrierTasks")]ProjectViewModel model)
    
        return View(model);
    

问题是:如何在这些视图中保持模型的状态,直到最终保存它?

我宁愿避免使用任何 hackish (TempData) 或 JS 依赖的解决方案,但如果它们真的是最好的解决方案,我不会拒绝这些。

谢谢, 亚当·托利

【问题讨论】:

【参考方案1】:

一个简单的解决方案是将 ViewModel 对象持久化到一个 Session 变量中并从这个源绑定视图。这当然不是最优雅的解决方案。另一种可能不太优雅的选择是将此模型数据保存在数据库中,并带有一些临时/未保存的标志。

【讨论】:

【参考方案2】:

问题在于,当您显示添加任务视图时,您没有为“项目”对象提供字段,因此 ModelState 会丢失与项目相关的数据,您需要提供此字段以确保您不会丢失这些数据。

您不需要显示这些字段,它们可以是隐藏类型,它们会保留值。只要确保如果您要绑定到视图模型,您需要像 Model.Project.Property 一样正确命名这些字段。

【讨论】:

所以我可以通过将它存储在客户端隐藏字段中来持久化它,有没有办法不依赖客户端存储?用这样一个相当大的模型来加载页面和浏览器感觉有点奇怪,只是为了在同一个控制器中保存跨方法/视图。感谢您的意见【参考方案3】:

也许我正在尝试解决错误的问题(ala Bruce Eckel)。我将尝试转移到不需要这种模糊边界的结构。我不想采用 REST 范式只是将它硬塞进一个有状态的应用程序中。

可能这些控件属于同一页面,我可以使用一些 JQuery 优点将其放入选项卡窗格中,以便于查看。

感谢那些回答的人,我发现每一个都很有用,一旦我有更多的代表,我会尽量记住给他们投票。

【讨论】:

【参考方案4】:

目前我无法评论其他人的问题,但唯一真正的选择是会话,如果您想在 Web 请求期间保持对象状态,或者将其序列化并将其放置在隐藏字段中。

或者最后的选择是更改页面的工作方式,以便在每次请求后保存对象...

如果您使用 nHibernate,那么您可能需要查看对话模式,但这实际上只是将 nHibernate 会话保存到 asp.net 会话中......

【讨论】:

我会将其标记为答案,因为它是最完整的选项集,并且包括 NHibernate 方法(尽管我目前坚持使用 EF1)。

以上是关于ASP.net MVC - 如何在各种视图中保留模型的主要内容,如果未能解决你的问题,请参考以下文章

asp.net mvc 如何实现自动提交或保留用户未登录前得信息

如何确定视图中动作的上下文(asp.net mvc)

ASP.NEt MVC 使用 Web API 返回 Razor 视图

在 ASP.NET MVC 中构造视图层次结构的最佳方法是啥?

ASP.NET MVC 视图引擎比较

ASP.NET MVC和AngularJs路由合并问题