Ok, after reading up on how to customize the default model binder, I think this bit of code just may do the trick of sorting the properties and will give me the desired binding order every time. Basically allowing me to bind the identity properties first (and thus allowing me to have my View Model trigger a 'load') allowing the remainder of the model binding process to function essentially as a merge!
''' <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
Then, I can register this in place of my DefaultModelBinder, and supply the most common property names that I'd like to have 'floated' to the top of the ModelBinding process...
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