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

发布于 2024-12-06 22:51:52 字数 372 浏览 0 评论 0原文

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

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

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

MyViewModel2 vModel2= new MyViewModel2();
InvokeModelBinder(vModel2);

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

Is there a way that I can invoke the model binder for a single object?

I don't want/need a custom model binder - I just want to do something like this:

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

MyViewModel2 vModel2= new MyViewModel2();
InvokeModelBinder(vModel2);

And when I'm done, the properties of both vModel1 and vModel2 have been bound to what's in the incoming request. Because of the way that our controller/action is being written, I don't necessarily want to list vModel1 and vModel2 in the action method's input list (since there will end up being a potentially long list of view models to optionally bind against).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦中楼上月下 2024-12-13 22:51:52

使用 Controller.UpdateModel

MyViewModel1 vModel1 = new MyViewModel1();
UpdateModel(vModel1);

更新

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

Use Controller.UpdateModel:

MyViewModel1 vModel1 = new MyViewModel1();
UpdateModel(vModel1);

Update

Note if ModelState in controller has validation errors (related to model passed in action), UpdateModel (with any model) throws excetion, despite UpdateModel success and vModel1 is updated. Therefore errors in ModelState should be removed, or put UpdateModel in try/catch and just ignore excetion

腹黑女流氓 2024-12-13 22:51:52

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

  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**);

您可以看到需要初始化 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;

}

This is wrong on many levels IMHO:

  1. This is not how ASP.NET MVC is designed to work.
  2. Your actions do not define a clear contract of what data they expect.
  3. What do you get out of it? Smells like bad design.

Model binding is driven by reflection. Before an action is invoked it will reflect the method parameters list and for each object and its properties it will invoke a model binder to find a value for each property from the various value providers (form POST values provider, url parameters, etc). During model binding the ModelState validation is done as well.

So by not using the default ASP.NET MVC to do this you are losing all that.

Even if you were to manually get hold of a model binder like that:

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

You can see that you need to initalize a ModelBindingContext, something that ASP.NET MVC will do internally based on the current property it is reflecting. Here is the snipped from the ASP.NET MVC source code:

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;

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文