问题
This question already has an answer here:
- How to set decimal separators in ASP.NET MVC controllers? 4 answers
Model binding in ASP.NET MVC is great, but it follows locale settings. In my locale decimal separator is comma (\',\'), but users use dot (\'.\') too, because they are lazy to switch layouts. I want this implemented in one place for all decimal
fields in my models.
Should I implement my own Value Provider (or event Model Binder) for decimal
type or I\'ve missed some simple way to do this?
回答1:
Cleanest way is to implement your own model binder
public class DecimalModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
return valueProviderResult == null ? base.BindModel(controllerContext, bindingContext) : Convert.ToDecimal(valueProviderResult.AttemptedValue);
// of course replace with your custom conversion logic
}
}
And register it inside Application_Start():
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
Credits : Default ASP.NET MVC 3 model binder doesn't bind decimal properties
回答2:
To properly handle group separator, just replace
Convert.ToDecimal(valueProviderResult.AttemptedValue);
in selected answer with
Decimal.Parse(valueProviderResult.AttemptedValue, NumberStyles.Currency);
回答3:
Thanks to accepted answer I ended up with the following implementation to handle float, double and decimal.
public abstract class FloatingPointModelBinderBase<T> : DefaultModelBinder
{
protected abstract Func<string, IFormatProvider, T> ConvertFunc { get; }
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null) return base.BindModel(controllerContext, bindingContext);
try
{
return ConvertFunc.Invoke(valueProviderResult.AttemptedValue, CultureInfo.CurrentUICulture);
}
catch (FormatException)
{
// If format error then fallback to InvariantCulture instead of current UI culture
return ConvertFunc.Invoke(valueProviderResult.AttemptedValue, CultureInfo.InvariantCulture);
}
}
}
public class DecimalModelBinder : FloatingPointModelBinderBase<decimal>
{
protected override Func<string, IFormatProvider, decimal> ConvertFunc => Convert.ToDecimal;
}
public class DoubleModelBinder : FloatingPointModelBinderBase<double>
{
protected override Func<string, IFormatProvider, double> ConvertFunc => Convert.ToDouble;
}
public class SingleModelBinder : FloatingPointModelBinderBase<float>
{
protected override Func<string, IFormatProvider, float> ConvertFunc => Convert.ToSingle;
}
Then you just have to set your ModelBinders on Application_Start
method
ModelBinders.Binders[typeof(float)] = new SingleModelBinder();
ModelBinders.Binders[typeof(double)] = new DoubleModelBinder();
ModelBinders.Binders[typeof(decimal)] = new DecimalModelBinder();
回答4:
var nfInfo = new System.Globalization.CultureInfo(lang, false)
{
NumberFormat =
{
NumberDecimalSeparator = "."
}
};
Thread.CurrentThread.CurrentCulture = nfInfo;
Thread.CurrentThread.CurrentUICulture = nfInfo;
来源:https://stackoverflow.com/questions/14400643/accept-comma-and-dot-as-decimal-separator