Custom Model Binder for decimals and integer: How to get the string value before MVC and do a smarter conversion
I want to extend the default model binding to be more smart whe开发者_C百科n dealing with numbers. The default works very bad when are commas and decimals points in the game.
I was trying the do a new binder
Public Class SmartModelBinder
Inherits DefaultModelBinder
Protected Overrides Sub SetProperty(controllerContext As ControllerContext, bindingContext As ModelBindingContext, propertyDescriptor As System.ComponentModel.PropertyDescriptor, value As Object)
If propertyDescriptor.PropertyType Is GetType(Decimal) Or propertyDescriptor.PropertyType Is GetType(Decimal?) Then
If value Is Nothing Then
value = 0
End If
End If
MyBase.SetProperty(controllerContext, bindingContext, propertyDescriptor, value)
End Sub
End Class
But the value is already converted at this point
How can I extend the binder to get the string value from the form and perform a different transformation?
What about this?
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder())
And a custom binder. I guess I don't know if you can override decimal binding in this way, but it works for my own types.
public class DecimalModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null)
{
return base.BindModel(controllerContext, bindingContext);
}
// to-do: your parsing (get the text value from valueProviderResult.AttemptedValue)
return parsedDecimal;
}
}
The method you are probably looking for is BindModel
. Here's a high level overview of how the default model binder works, suppose you have the following class:
public class MyModel
{
public int Id;
public string Name;
}
When MVC tries to bind data to MyModel
, it calls BindModel
on the default model binder. That binder determines that MyModel
is not a "simple" data type (i.e. int
, decimal
, string
etc). It then pulls out the possible members that it can bind to, then finds the correct model binder for each of those types and calls that model binder's BindModel
method against the field/property, so model binding of a complex type is really a recursive call.
Normally I would suggest writing a model binder just for decimal and setting that as the model binder for that data type, but I've heard others have had issue with that (I haven't tried it myself). So I would try that first, and if that doesn't work, then just check for that model type in the BindModel
method of your default model binder and handle that special case.
This is an extremely high level overview of model binding and wouldn't even begin to suggest that it's everything you need to know about how that area works.
I'm adding an additional answer because Phil Haack blogged recently on exactly how to do this. He warns that it is untested, but he makes use of the ModelState
and adds an error if needed, which is something I was never aware of when/how to do, so it was helpful to me.
Here's a link to his post: http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx
精彩评论