问题
I have a model that has an integer property. When the model is submitted with 23443
, the model binder works great and the value is available in the action. But if the model is submitted with a thousands separator like 23,443
, the value isn't parsed and the property is zero. But I found that a property with the type of decimal could have the thousands separator and it would parse and be populated correctly.
I found out that by default Int32.Parse() doesn't parse thousands separator but Decimal.Parse()
does allow thousands separator. I don't want to have to write a check like:
public ActionResult Save(Car model, FormCollection form) {
Int32 milage;
if(model.MyProperty == 0 && Int32.TryParse(form["MyProperty"], NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out milage) {
model.MyProperty = milage;
} else
ModelState.AddModelError("Invalid", "Property looks invalid");
[...]
}
every time I deal with these fields. It looks ugly, and moves all the validation out of the model attributes. Changing the type of the property to decimal just to make the model binding work doesn't seem like a smart idea. When I look into the model binder, it looks like it's using TypeConverter
to complete the conversions from string to the type. And it looks like Int32Converter uses Int32.Parse() with NumberStyles.Integer.
Is there a way to change the behavior of Int32Converter
to allow the thousands separator to be parsed by default? Maybe override the default NumberStyles
on Int32.Parse()
across the entire app? Or is adding my own model binder which parses the integers with NumberStyles.AllowThousands
the only/correct course of action?
回答1:
I think, you can add custom binder for int type.
Demo: http://dotnetfiddle.net/VSMQzw
Useful links:
- http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx/
- Default ASP.NET MVC 3 model binder doesn't bind decimal properties
- http://www.codeproject.com/Articles/551576/ASP-NET-MVC-Model-Binding-and-Data-Annotation
updated
Based on Haacked article:
using System;
using System.Globalization;
using System.Web.Mvc;
public class IntModelBinder : IModelBinder
{
#region Implementation of IModelBinder
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
ModelState modelState = new ModelState { Value = valueResult };
bindingContext.ModelState[bindingContext.ModelName] = modelState;
object actualValue = null;
try
{
actualValue = Int32.Parse(valueResult.AttemptedValue, NumberStyles.Number, CultureInfo.InvariantCulture);
}
catch (FormatException e)
{
modelState.Errors.Add(e);
}
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return actualValue;
}
#endregion
}
And in the Application_Start event (probably in the Global.asax), add:
ModelBinders.Binders.Add(typeof(int), new IntModelBinder());
来源:https://stackoverflow.com/questions/21189158/change-default-numberstyles-on-integers