UpdateModel()是什么作用?

11

通俗易懂地讲,UpdateModel()TryUpdateModel()是做什么的?我在Stack Overflow或者其他网站上都找不到简单易懂的解释,只看到人们讨论使用它们遇到的问题。

即使在VisualStudio的智能提示下也无济于事。我之所以提问是因为,比如说,在我的控制器中有这样一段代码:

[HttpPost]
public ActionResult Index( UserViewModel vm, FormCollection form)
{    
  var statesCheckBoxes = form["StatesList"];       

  vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>();

  return View(vm);
}
我已经通过设置vm.BA.StatesTraveledTo更新了我的模型,那我为什么还需要运行UpdateModel呢?另外,当我实际尝试执行以下操作时:
[HttpPost]
public ActionResult Index( UserViewModel vm, FormCollection form)
{    
  var statesCheckBoxes = form["StatesList"];       

  vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>();

  UpdateModel(vm); // IS THIS REDUNDANT TO THE PREVIOUS LINE?

  return View(vm);
}

当我检查ModelState的值(在运行UpdateModel()之后)时,似乎什么都没有发生。我没有看到任何指示有任何更改的东西。我在ModelState字典中没有看到新键。

真的很困惑。谢谢!

编辑:

发布ViewModel和Model类的源代码:

public class UserViewModel
{
  public BankAccount BA { get; set; }
}

public class BankAccount
{
  public Person User { get; set; }
  public List<string> StatesTraveledTo { get; set; }
}

public class Person
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public int Age { get; set; }
}

1
这是它的源代码:http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266451。它非常简单,只需创建一个ModelBindingContext并将其绑定即可。 - George Mauer
1
此外,在将输入作为操作传递到视图中时,很少会传递与接收到的相同对象,虽然这种情况偶尔会发生,但并不常见,而且这似乎不是其中之一。通常,您会将代表所发布数据的对象作为输入,并为视图创建一个单独的模型。 - George Mauer
谢谢。我将模型传回视图的原因是为了验证目的。因此,如果验证失败,我希望将模型及其值传递到视图,以便表单字段得到重新填充并显示错误消息。抱歉,我想用我展示的代码可能看起来不像一个实际的例子。 - SaltProgrammer
1
我明白了,那样更有意义。但我仍不会使用FormCollection,而是会创建一个专门的类来存储我期望传递的所有值。 - George Mauer
3个回答

7
当你写作时会发生什么。
public ActionResult Index( UserViewModel vm)
{    }

当您检查 ActionResult 时,您会发现 vm 包含从视图中提交的值。这是因为MVC指示模型绑定器从不同的来源(表单集合、路由值、查询字符串等)提取值并填充模型的值。但是,要实现这一点,您的表单键必须与模型中属性的名称匹配,如果是这种情况,则正确填充了模型。现在我们来到实际问题:UpdateModel 是什么?简单的答案是什么都没有,只是模型绑定。唯一的区别是您明确调用它。上面的 ActionResult 可以使用 UpdateModel 重写。
Public ActionResult Index ()
{
   UserViewModel vm = new UserViewModel();
   UpdateModel(vm);// it will do same thing that was previously handled automatically by mvc
}

现在,自动模型绑定未处理的内容也不会被显式模型绑定处理,因为这不是与模型绑定器有关的问题,而是与您的HTML有关的问题。对于像您这样嵌套的视图模型,表单字段名称必须仔细制作,以便MVC可以正确地将其注入到您的模型中,而无需编写类似以下的代码。
vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>(); 

如果您不想这样做,请查看此谷歌搜索

2
这是它的源代码:http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266451。它相当简单,
    protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IDictionary<string, ValueProviderResult> valueProvider) where TModel : class {
        if (model == null) {
            throw new ArgumentNullException("model");
        }
        if (valueProvider == null) {
            throw new ArgumentNullException("valueProvider");
        }

        Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);
    IModelBinder binder = Binders.GetBinder(typeof(TModel));

    ModelBindingContext bindingContext = new ModelBindingContext() {
        Model = model,
        ModelName = prefix,
        ModelState = ModelState,
        ModelType = typeof(TModel),
        PropertyFilter = propertyFilter,
        ValueProvider = valueProvider
    };
    binder.BindModel(ControllerContext, bindingContext);
    return ModelState.IsValid;
}

这只是创建了一个ModelBindingContext并进行绑定。我相信在调用您的操作之前,默认情况下已经发生了。很少需要手动调用它。

仅仅是猜测,但您可能会因为使用了非典型的方式而获得奇怪的结果。您的操作签名:

public ActionResult Index( UserViewModel vm, FormCollection form)

需要传入UserViewModel和FormCollection。通常人们会选择其中一种(实际上,现在很少使用FormCollection)。再次提醒,我凭记忆猜测UpdateModel不起作用是因为这些值已经绑定了。如果它为空,那么可能是因为FormCollection接收(绑定)了您提交的所有值,没有留下任何值供视图模型绑定。


不好意思,我是个新手。你的意思是说UpdateModel()在我的操作之前默认运行,因此无需从操作中显式运行吗?谢谢。 - SaltProgrammer
我使用FormCollection的原因是默认的模型绑定器(用于ViewModel)无法将我在视图上拥有的一组复选框与UserViewModel对象内的BankAccount对象中的List属性绑定。请查看我刚刚添加到问题中的源代码。为了正确映射这个深度嵌套的属性,我直接从FormCollection中获取它。我知道另一种不使用FormCollection对象的方法是创建一个自定义模型绑定器,但我不想让它变得更加复杂,或者我错过了什么吗? - SaltProgrammer
1
是的,只需为您希望具有相应复选框类型的其他值创建一个类。如果它可以绑定到FormCollection,那么应该可以将其绑定到静态类型。您还可以从请求对象中获取所需内容。 - George Mauer

0

更新模型基本上用于在现有模型中更新新值。您不需要显式地分配值。


你是说我不必这样做吗...vm.BA.StatesTraveledTo = statesCheckBoxes.Split(',').ToList<string>();???如果我不需要那样做,那么如果我只想使用UpdateModel()方法,该怎么写语法呢? - SaltProgrammer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接