由于未在下拉框列表中发送所有数据,因此当modelstate无效时必须重新填充viewmodel

时间:2013-10-12 16:55:47

标签: .net asp.net-mvc-4 asp.net-mvc-viewmodel asp.net-mvc-views

在我的项目中,我创建了一项调查,我将此调查链接到公司并选择要参与的用户。我选择调查模板,添加额外的问题并设置有关调查的信息,如开始和结束日期。

总而言之,结果是一个复杂的视图,其中包含来自域的许多部分的数据。 我为这个视图创建了一个ViewModel,其中包括所有公司的列表(因为我需要在下拉列表中选择公司)。

现在令人烦恼的是,当我提交保存时,如果我有一个模型状态错误,那么我想重新显示视图,但因为我所提取的所有数据,如所有公司的列表都没有从客户端发送(即使是viewmodel支持它)我必须在再次显示表单之前再次填充所有列表/变量。

我想我可以创建一个创建下拉列表的视图,但是因为下拉需要将它的值插入到我在CompanyId下的调查中,这也不是很明显。

我认为自定义模型绑定器也可以做到这一点。我在这里要求感受那里最好的解决方案。如果我想重新考虑整个战略。

2 个答案:

答案 0 :(得分:2)

模型绑定器可能有助于该过程,但我不认为它是一个完整的解决方案。首先,模型绑定器在实例化模型时可能无法“知道”您的意图。例如,如何知道您稍后在操作方法中认为模型无效?

我通常有一个单独的方法(甚至是一个单独的类),其唯一目的是管理构建适合于该情况的视图模型的数据。

然后,action方法告诉这个帮助器它想要什么,允许它作为进程的调控器服务于它的目的。例如,控制器可以决定:

  • 需要准备一个新的视图模型。
  • 需要准备一个新的视图模型,但使用查询字符串中的值初始化select属性。
  • 应构建视图模型以表示现有的域模型。
  • 应保留视图模型的用户编写数据,但应重建其他字段(例如,您的下拉列表示例)。

我将这个视图模型称为“组合”。从本质上讲,您将向视图呈现完整视图模型所需的数据汇总在一起。这些数据可能来自各个地方。

我描述了composition process in more detail here。我已经编写了一个完整的框架来支持ASP.Net MVC的组合模式(闭源,仅仅是因为时间)。我发现它使得支持复杂的视图模型变得更加容易,并且极大地改进了我的代码重用。

简单示例

此示例将进程保留在控制器内(而不是单独的类),并专注于指定一些简单的选项。

[Flags]
public enum CompositionOptions
{
    PopulateFromDomainModel = 1,
    Hydrate = 2
}

[HttpGet]
public ActionResult Edit( int id)
{
    var model = new ViewModel();
    // the controller states exactly what it wants
    Compose( model, CompositionOptions.PopulateFromDomainModel | CompositionOptions.Hydrate, id );
}

[HttpPost]
public ActionResult Edit( ViewModel model )
{
    if( !ModelState.IsValid )
    {
        // Rebuild values which weren't contained in the POST. Again, the
        // controller states exactly what it needs.
        Compose( model, CompositionOptions.Hydrate );
        return View( model );
    }

    // Use POST-redirect-GET pattern, allowing the page to reload with the changes
    return RedirectToAction( "Edit", new { id = model.Id } );
}

private void Compose( ViewModel model, CompositionOptions options, int? id = null )
{
    // This logic can become quite complex, but you are generally checking for
    // existing data source (domain models) and what you should populate and
    // what fields you should preserve.

    if( id != null && options.HasFlag( CompositionOptions.PopulateFromDomainModel ) )
    {
        // get your domain model from a repository and populate the 
        // properties of the view model
    }

    if( options.HasFlag( CompositionOptions.Hydrate ) )
    {
        // set values on the view model which won't be included in 
        // a POST, and thus must be rebuilt with every roundtrip
    }
}

答案 1 :(得分:1)

一种可能性肯定是Tim建议的自动补液。

然而,我最终采用的方法是Tim G Thomas在此提出的建议:http://timgthomas.com/2013/09/simplify-client-side-validation-by-adding-a-server/

这意味着除非数据有效,否则数据永远不会离开客户端,这意味着需要再次进行补液。 它确实需要javascript,这对我来说是可以接受的,因为你再也不需要为视图补充水分了。