Omar Martinez Omar Martinez - 17 days ago 11
C# Question

Decimal.Parse strange behavior on Chrome and Firefox

In a MVC project, I have a variable set in the web.Config of my project like this:

enter image description here

Then in my code, I get that variable and parse it as decimal:

enter image description here

enter image description here

As you can see, this works fine, the problem is that when I run my code on Google Chrome or Mozilla Firefox, I have diferent results:

enter image description here

enter image description here

I dont undestand why that happens, as not happen in all machines that run the web on Chrome, all I can think is that it seems to be something on the browser config but its a standard instalation, nothing different.

Anyone can point me in the right direction? Or has an idea of what can be causing this behavior?

UPDATE:

Code in text (I don't know why, but ok)

For easy-debugging I have this:

public static decimal ServiceFee
{
get
{
var webConfigVar = ConfigurationManager.AppSettings["ServiceFee"];
decimal webConfigVarDecimal = decimal.Parse(webConfigVar ?? "0");
return webConfigVarDecimal;
}
}


Normally, is like this

public static decimal ServiceFee
{
get
{
return decimal.Parse(ConfigurationManager.AppSettings["ServiceFee"] ?? "0");
}
}


And the Web.Config

<appSettings>
<add key="ServiceFee" value="0.024" />
</appSettings>


UPDATE 2

I know that the code run on the server, but the only difference is the Browser, and its always with those browsers on a few machines.

No matter if the server is running local or on production

Dai Dai
Answer

Decimal.Parse uses the CultureInfo of the current request request-handling thread, which ASP.NET can (though not by default) set according to the browser's Accept header - so that browsers set to French or German will use their formatting rules (where comma ',' is the radix place, not a dot '.'). This is probably what's happening: your Chrome browser is set to use a different culture.

The fix is to specify CultureInfo.InvariantCulture when calling any Parse or ToString method if it is interacting with human-readable text (e.g. when loading a config file).

This is why static analysis is important (the "Analyze" menu in Visual Studio) - it can point out these bugs.

(My own personal opinion is that the Parse method should be removed from .NET and replaced with explicit ParseFormatted(IFormatProvider, String) and ParseInvariant(String) - but that's just me :)

I note that is inefficient to always call Parse in your property-getter. You should just cache it statically (using the new C# 6.0 read-only property syntax):

using System.Globalization;

public static decimal ServiceFee { get; } =
        Decimal.Parse(
            ConfigurationManager.AppSettings["ServiceFee"] ?? "0",
            NumberStyles.Number,
            CultureInfo.InvariantCulture
        );

If you do this frequently you might want a reusable method:

public static Decimal GetAppSettingDecimal(String name) {

    String textualValue = ConfigurationManager.AppSettings[ name ];
    Decimal ret;
    return Decimal.TryParse( textualValue, NumberStyles.Number, CultureInfo.InvariantCulture, out ret ) ? ret : 0;
}

public static Decimal ServiceFee { get; } = GetAppSettingDecimal("ServiceFee");