I'm working with the NerdDinner application trying to teach myself ASP.NET MVC. However, I have stumbled upon a problem with globalization, where my server presents floating point numbers with a comma as the decimal separator, but Virtual Earth map requires them with dots, which causes some problems.
I have already solved the issue with the mapping JavaScript in my views, but if I now try to post an edited dinner entry with dots as decimal separators the controller fails (throwing InvalidOperationException
) when updating the model (in the UpdateModel()
metod). I feel like I must set the proper culture somewhere in the controller as well, I tried it in OnActionExecuting()
but that didn't help.
I have just revisited the issue in a real project and finally found a working solution. Proper solution is to have a custom model binder for the type decimal
(and decimal?
if you're using them):
using System.Globalization; using System.Web.Mvc; public class DecimalModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { object result = null; // Don't do this here! // It might do bindingContext.ModelState.AddModelError // and there is no RemoveModelError! // // result = base.BindModel(controllerContext, bindingContext); string modelName = bindingContext.ModelName; string attemptedValue = bindingContext.ValueProvider.GetValue(modelName)?.AttemptedValue; // in decimal? binding attemptedValue can be Null if (attemptedValue != null) { // Depending on CultureInfo, the NumberDecimalSeparator can be "," or "." // Both "." and "," should be accepted, but aren't. string wantedSeperator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; string alternateSeperator = (wantedSeperator == "," ? "." : ","); if (attemptedValue.IndexOf(wantedSeperator, StringComparison.Ordinal) == -1 && attemptedValue.IndexOf(alternateSeperator, StringComparison.Ordinal) != -1) { attemptedValue = attemptedValue.Replace(alternateSeperator, wantedSeperator); } try { if (bindingContext.ModelMetadata.IsNullableValueType && string.IsNullOrWhiteSpace(attemptedValue)) { return null; } result = decimal.Parse(attemptedValue, NumberStyles.Any); } catch (FormatException e) { bindingContext.ModelState.AddModelError(modelName, e); } } return result; } }
Then in Global.asax.cs in Application_Start():
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder()); ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
Note that code is not mine, I actually found it at Kristof Neirynck's blog here. I just edited a few lines and am adding the binder for a specific data type, not replacing the default binder.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With