asp.net-mvc 如何在 ASP.NET MVC 控制器中设置小数点分隔符?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/793459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set decimal separators in ASP.NET MVC controllers?
提问by Pawel Krakowiak
I'm working with the NerdDinnerapplication 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.
我正在使用NerdDinner应用程序尝试自学 ASP.NET MVC。然而,我偶然发现了一个全球化的问题,我的服务器用逗号作为小数点分隔符来显示浮点数,但虚拟地球地图要求它们带有点,这会导致一些问题。
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.
我已经在我的视图中解决了映射 JavaScript 的问题,但是如果我现在尝试发布一个编辑的晚餐条目,其中点作为小数点分隔符,则控制器InvalidOperationException在更新模型时失败(抛出)(在UpdateModel()方法中)。我觉得我也必须在控制器的某处设置适当的文化,我试过了,OnActionExecuting()但没有帮助。
回答by Pawel Krakowiak
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):
我刚刚在一个实际项目中重新审视了这个问题,并最终找到了一个可行的解决方案。正确的解决方案是为该类型使用自定义模型绑定器decimal(decimal?如果您正在使用它们):
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():
然后在 Application_Start() 中的 Global.asax.cs 中:
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.
请注意,代码不是我的,实际上是我在 Kristof Neirynck 的博客上找到的。我刚刚编辑了几行,并为特定数据类型添加了活页夹,而不是替换默认活页夹。
回答by Nick Berardi
Set this in your web.config
在你的 web.config 中设置
<system.web>
<globalization uiCulture="en" culture="en-US" />
You appear to be using a server that is setup with a language that uses comma's instead of decimal places. You can adjust the culture to one that uses the comma's in a way that your application is designed, such as en-US.
您似乎正在使用使用逗号而不是小数位的语言设置的服务器。您可以将区域性调整为以应用程序设计的方式使用逗号的区域性,例如 en-US。
回答by Steve
Can you parse the text using the invariant culture - sorry, I don't have the NerdDinner code in fornt of me, but if you are passing in dot-separated decimals than the parsing should be OK if you tell it to use the invariant culture. E.g.
您能否使用不变文化解析文本 - 抱歉,我没有 NerdDinner 代码,但是如果您传入点分隔小数,那么如果您告诉它使用不变文化,那么解析应该没问题. 例如
float i = float.Parse("0.1", CultureInfo.InvariantCulture);
Edit. I suspect that this is a bug in the NerdDinner code by the way, along the same lines as your previous problem.
编辑。顺便说一下,我怀疑这是 NerdDinner 代码中的一个错误,与您之前的问题相同。
回答by Colin Wiseman
I have a different take on this, you might like it. What I don't like about the accepted answer is it doesn't check for other characters. I know there will be a case where the currency symbol will be in the box because my user doesn't know better. So yeah I can check in javascript to remove it, but what if for some reason javascript isn't on? Then extra characters might get through. Or if someone tries to spam you passing unknown characters through... who knows! So I decided to use a regex. It's a bit slower, tiny fraction slower - for my case it was 1,000,000 iterations of the regex took just under 3 seconds, while around 1 second to do a string replace on a coma and period. But seeing as I don't know what characters might come through, then I am happy for this slightest of performance hits.
我对此有不同的看法,你可能会喜欢。我不喜欢接受的答案是它不检查其他字符。我知道会出现货币符号出现在框中的情况,因为我的用户并不了解。所以是的,我可以检查 javascript 以将其删除,但是如果由于某种原因 javascript 没有打开怎么办?然后额外的字符可能会通过。或者,如果有人试图通过垃圾邮件向您发送未知字符……谁知道呢!所以我决定使用正则表达式。它有点慢,慢一点 - 就我而言,正则表达式的 1,000,000 次迭代只用了不到 3 秒,而在昏迷和周期上进行字符串替换大约需要 1 秒。但是看到我不知道会出现哪些角色,那么我很高兴看到这一点的表现。
public class DecimalModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
string modelName = bindingContext.ModelName;
string attemptedValue =
bindingContext.ValueProvider.GetValue(modelName).AttemptedValue;
if (bindingContext.ModelMetadata.IsNullableValueType
&& string.IsNullOrWhiteSpace(attemptedValue))
{
return null;
}
if (string.IsNullOrWhiteSpace(attemptedValue))
{
return decimal.Zero;
}
decimal value = decimal.Zero;
Regex digitsOnly = new Regex(@"[^\d]", RegexOptions.Compiled);
var numbersOnly = digitsOnly.Replace(attemptedValue, "");
if (!string.IsNullOrWhiteSpace(numbersOnly))
{
var numbers = Convert.ToDecimal(numbersOnly);
value = (numbers / 100m);
return value;
}
else
{
if (bindingContext.ModelMetadata.IsNullableValueType)
{
return null;
}
}
return value;
}
}
Basically, remove allcharacters that are not digits, for a string that isn't empty. Convert to decimal. Divide by 100. Return result.
基本上,对于非空的字符串,删除所有不是数字的字符。转换为十进制。除以 100。返回结果。
Works for me.
对我来说有效。

