4

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

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

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

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

我认为自定义模型绑定器也可以解决问题。我在这里要求对那里的最佳解决方案有所了解。如果我宁愿重新考虑整个战略。

4

2 回答 2

2

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

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

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

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

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

在这里更详细地描述了合成过程。我已经编写了一个完整的框架来支持 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
    }
}
于 2013-10-12T20:46:44.507 回答
1

一种可能性当然是蒂姆建议的自动补液。

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

这意味着数据永远不会离开客户端,除非它是有效的,这意味着不需要再水化。它确实需要 javascript,这对我来说是可以接受的,因为您再也不需要重新水化视图。

于 2014-10-12T10:19:48.993 回答