MVC直接在单个对象上调用模型绑定器

Kra*_*ras 8 model-binding viewmodel asp.net-mvc-3

有没有办法可以为单个对象调用模型绑定器?

我不想/需要自定义模型绑定器 - 我只想做这样的事情:

MyViewModel1 vModel1 = new MyViewModel1();
InvokeModelBinder(vModel1);

MyViewModel2 vModel2= new MyViewModel2();
InvokeModelBinder(vModel2);
Run Code Online (Sandbox Code Playgroud)

当我完成后,vModel1和vModel2的属性已经绑定到传入请求中的内容.由于我们的控制器/操作的编写方式,我不一定要在操作方法的输入列表中列出vModel1和vModel2(因为最终会有一个可能很长的视图模型列表,可以选择绑定).

Sel*_*Sel 8

使用Controller.UpdateModel:

MyViewModel1 vModel1 = new MyViewModel1();
UpdateModel(vModel1);
Run Code Online (Sandbox Code Playgroud)

更新

请注意,如果ModelState控制器中存在验证错误(与传递的模型相关),则UpdateModel(使用任何模型)会抛出异常,尽管UpdateModel成功并且vModel1已更新.因此,应删除ModelState中的错误,或将UpdateModel放在try/catch中,并忽略省略


Iva*_*tev 2

恕我直言,这在很多层面上都是错误的:

  1. 这不是 ASP.NET MVC 的设计工作方式。
  2. 您的行为并没有定义他们期望的数据的明确合同。
  3. 你从中得到什么?闻起来像是糟糕的设计。

模型绑定由反射驱动。在调用操作之前,它将反映方法参数列表,并且对于每个对象及其属性,它将调用模型绑定器以从各种值提供程序(表单 POST 值提供程序、url 参数等)中查找每个属性的值。在模型绑定期间,也会完成 ModelState 验证。

因此,如果不使用默认的 ASP.NET MVC 来执行此操作,您将失去所有这些。

即使您要手动获取这样的模型绑定器:

IModelBinder modelBinder = ModelBinders.Binders.GetBinder(typeof(MyObject));
MyObject myObject = (MyObject ) modelBinder.BindModel(this.ControllerContext, ** ModelBindingContext HERE**);
Run Code Online (Sandbox Code Playgroud)

您可以看到,您需要初始化 ModelBindingContext,ASP.NET MVC 将根据它所反映的当前属性在内部执行此操作。以下是 ASP.NET MVC 源代码的片段:

protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) {
// collect all of the necessary binding properties
Type parameterType = parameterDescriptor.ParameterType;
IModelBinder binder = GetModelBinder(parameterDescriptor);
IDictionary<string, ValueProviderResult> valueProvider = controllerContext.Controller.ValueProvider;
string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
Predicate<string> propertyFilter = GetPropertyFilter(parameterDescriptor);

// finally, call into the binder
ModelBindingContext bindingContext = new ModelBindingContext() {
    FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefix not specified
    ModelName = parameterName,
    ModelState = controllerContext.Controller.ViewData.ModelState,
    ModelType = parameterType,
    PropertyFilter = propertyFilter,
    ValueProvider = valueProvider
};
object result = binder.BindModel(controllerContext, bindingContext);
return result;
Run Code Online (Sandbox Code Playgroud)

}