我的问题与this stack overflow question中提出的情况基本相同,我发现自己想要从数据库加载现有的有效版本的模型,并将其中的一部分更新为某个字段的子集暴露在我的网络表格上。
无论如何,我可以让模型绑定过程保证我的ID属性首先被绑定吗?
如果我可以保证这一点,那么,在我的ViewModel的ID属性的setter中,我可以触发'load',以便最初从DB(或WCF服务..或Xml文件)填充该对象。或者其他选择的存储库)然后,随着MVC完成模型绑定过程,从FORM帖子提交的其余属性整齐地合并到对象中。
然后,我的IValidatableObject.Validate方法逻辑将很好地告诉我结果对象是否仍然有效......依此类推......
在我看来,我必须编写管道,其中我有两个模型实例(knownValidDomainModelInstanceFromStorage,postedPartialViewModelInstanceFromForm)然后手动映射到所需的属性是重复一些真正已经由MVC处理的东西......如果我能只控制身份的绑定顺序。
编辑 - 我发现属性绑定顺序可以使用自定义绑定器进行操作。非常简单地。阅读我在下面发布的答案。仍然欢迎您的反馈或意见。
答案 0 :(得分:0)
好的,在阅读了如何自定义默认模型绑定器之后,我认为这段代码可能会对排序属性进行排序,并且每次都会给我所需的绑定顺序。基本上允许我首先绑定标识属性(从而允许我让我的视图模型触发'加载'),允许模型绑定过程的其余部分基本上作为合并运行!
''' <summary>
''' A derivative of the DefaultModelBinder that ensures that desired properties are put first in the binding order.
''' </summary>
''' <remarks>
''' When view models can reliably expect a bind of their key identity properties first, they can then be designed trigger a load action
''' from their repository. This allows the remainder of the binding process to function as property merge.
''' </remarks>
Public Class BindIdFirstModelBinder
Inherits DefaultModelBinder
Private commonIdPropertyNames As String() = {"Id"}
Private sortedPropertyCollection As ComponentModel.PropertyDescriptorCollection
Public Sub New()
MyBase.New()
End Sub
''' <summary>
''' Use this constructor to declare specific properties to look for and move to top of binding order.
''' </summary>
''' <param name="propertyNames"></param>
''' <remarks></remarks>
Public Sub New(propertyNames As String())
MyBase.New()
commonIdPropertyNames = propertyNames
End Sub
Protected Overrides Function GetModelProperties(controllerContext As ControllerContext, bindingContext As ModelBindingContext) As ComponentModel.PropertyDescriptorCollection
Dim rawCollection = MyBase.GetModelProperties(controllerContext, bindingContext)
Me.sortedPropertyCollection = rawCollection.Sort(commonIdPropertyNames)
Return sortedPropertyCollection
End Function
End Class
然后,我可以注册这个代替我的DefaultModelBinder,并提供我想要“浮动”到ModelBinding进程顶部的最常见的属性名称......
Sub Application_Start()
RouteConfig.RegisterRoutes(RouteTable.Routes)
BundleConfig.RegisterBundles(BundleTable.Bundles)
' etc... other standard config stuff omitted...
' override default model binder:
ModelBinders.Binders.DefaultBinder = New BindIdFirstModelBinder({"Id", "WorkOrderId", "CustomerId"})
End Sub