Thursday, October 23, 2008

Mvc Framework Model Binders

In the preview 5 version of the asp.net mvc framework they introduced the ModelBinder. The team at my company actually started a very similar implementation for use with nHibernate. Unfortunately, it - like the project - never really took off. So along comes the mvc framework and the ModelBinder. Preview 5 supports built in support for basic binding, but allows you to build your own custom binding. 

As I mentioned in a previous post, I'll be a little different and post this example using vb.net code. Truth to be told, I prefer C#, but there seems to be a real lack of vb.net examples so far. 

To add custom binding/serialization support for your custom class it needs to implement IModelBinder. There's only one required method to implement which is GetValue() in which you take the form from the controllerContext.HttpContext.Request object and map the fields to your class. Here's a sample:


<modelbinder(GetType(fedloanrule))> _

Partial Public Class FedLoanRule

  Implements IModelBinder

    Public Function GetValue(ByVal controllerContext As System.Web.Mvc.ControllerContext, ByVal modelName As String, ByVal modelType As System.Type, ByVal modelState As System.Web.Mvc.ModelStateDictionary) As Object
  Implements System.Web.Mvc.IModelBinder.GetValue

        Dim request As HttpRequestBase = controllerContext.HttpContext.Request
        Dim rule As FedLoanRule = New FedLoanRule()

        rule.LoanType = request("LoanType")
        rule.LateDisbInterval = Integer.Parse(request("LateDisbInterval"))
        rule.MaxCombinedDepLoan = Integer.Parse(request("MaxCombinedDepLoan"))
        rule.MaxCombinedGradLoan = Integer.Parse(request("MaxCombinedGradLoan"))
        Return rule

    End Function
End Class


When an instance of a FedLoanRule is passed into my controller action, GetValue is called first. This would be useful if you had some special mapping that had to be done since it takes the mapping code out of your save/update code. In this simple case it would seem that it would have been easier just to call TryUpdateModel(). But this is good for an example. 

When the code gets into the controller action, the updated object instance is there and ready to use. Here's the catch. As of the Preview 5 version (I say that because the beta was just released),  this only seems to be useful for creating new records. If you want to do an update, even though your object is bound to the form prior to reaching your controller action, once in the controller action the Model does not see that anything has been changed. You have to retrieve the object from the model, make your change and then you can do the update. If you just call SubmitChanges()  on the object that is passed in from GetValue(), nothing is submitted. 

While it's cool functionality, it doesn't seem to make a whole lot of sense to have separate methods for inserting new records - a scenerio in which the model binder does work - and for updating existing records. 

Hey, this is still preview code and I've yet to try out the beta. Somebody else brought up this point on ScottGu's blog. And he mentioned that it might be addressed in the beta. 

No comments:

Post a Comment