Decimal.Parse strange behavior on Chrome and Firefox - c#

In a MVC project, I have a variable set in the web.Config of my project like this:
Then in my code, I get that variable and parse it as decimal:
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:
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

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");

Related

DateTime.ToString format inconsistent between Web App and Windows Service

We are experiencing weird behaviour between a web application and windows service when trying to perform a ToString() on a DateTime value.
See the example below.
DateTime parsedReportDate;
reportDate = DateTime.Now.ToString("yyyyMMdd");
reportDateWithSlash = DateTime.Now.ToString("dd/MM/yyyy");
if (DateTime.TryParse(MyDateValue, out parsedReportDate))
{
reportDate = parsedReportDate.ToString("yyyyMMdd");
reportDateWithSlash = parsedReportDate.ToString("dd/MM/yyyy");
}
--reportDateWithSlash on Web Application: 28/03/2017
--reportDateWithSlash on Windows Service: 28-03-2017
The Windows Service calls the same function as the Web Application does, so why is the formatting different then?
The formatting of dates to strings uses a CultureInfo object to know what format to use.
Each Thread has a Thread.CurrentCulture property.
You can find out what CultureInfo the current Thread is set by getting the current Thread using Thread.CurrentThread and then inspecting it's Thread.CurrentCulture property.
public class Program
{
public static void Main()
{
Console.WriteLine(Thread.CurrentThread.CurrentCulture.Name);
}
}
https://dotnetfiddle.net/dsA3VT
Output: en-US
You can set the CultureInfo for the the Thread, or pass it with each call to ToString.
Setting Thread.CultureInfo
You can set the Thread.CultureInfo using the same property as you use to read it.
Thread.CurrentCulture = new CultureInfo("en-gb");
Unfortunately .Net Fiddle doesn't support changing thread properties.
I didn't know this, but bradbury9 pointed out that since .net 4.6 you can set the CultureInfo.CurrentCulture property as well.
CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("nl-NL");
Unfortunately .Net Fiddle doesn't support changing the culture this way either.
Passing CultureInfo to ToString
'DateTime.ToString' has overloads which can take an IFormatProvider, and CultureInfo impliments IFormatProvider.
DateTime.Now.ToString(new CultureInfo("en-gb"));
https://dotnetfiddle.net/qkS5HF
public class Program
{
public static void Main()
{
var dateTime = DateTime.Now;
Console.WriteLine(Thread.CurrentThread.CurrentCulture.Name);
Console.WriteLine(dateTime.ToString(CultureInfo.InvariantCulture));
Console.WriteLine(dateTime.ToString(new CultureInfo("en-us")));
}
}
Output:
en-US
03/28/2017 09:43:49
3/28/2017 9:43:49 AM
The problem must come from having different cultures. Using the DateTime.ToString (String, IFormatProvider) overload with the CultureInfo.InvariantCulture property should solve the problem:
DateTime.Now.ToString("dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
it may be what is calling the Windows service is formatting the date. the code certainly is clear enough. Try debugging the windows service by attaching to the running process and see what it generates. If your service consumer is a web app, look at F12 developer tools and see what is getting sent back int he response stream.

Currency Symbol Display Is Incorrect

The currency symbol and currency format for this language code is displaying incorrectly when called through C# on a server.
ms-MY (Malay - Malaysian)
The language display on the control panel on the server has the currency symbol set to RM. While debugging the C# code, it has the currency code set to R.
I wrote up a mini console program locally to display the currency symbol for ms-MY and it shows up as RM.
If I change the formatting on the server. The code doesn't pick up the changes. Anyone knows if there are weird server caches or another place that language settings are stored?
I've checked the language registry key between the server and my local machine and they are the same. I tried recycling the application pool and it still doesn't work.
Pseudo Code on the server
foreach (CultureInfo c in CultureInfo.GetCultures(CultureTypes.InstalledWin32Cultures))
{
if (c.ThreeLetterISOLanguageName != "IVL")
{
r = new RegionInfo(c.LCID);
if (r.ISOCurrencySymbol == isoCurrencyCode)
{
ci = c;
FoundCode = true;
break;
}
}
}
Mini Console Code for testing locally.
decimal amount = 179835.00M ;
Console.WriteLine(amount.ToString("C", CultureInfo.CreateSpecificCulture("ms-my")));
Note when I add this to the watcher on the server code: CultureInfo.CreateSpecificCulture("ms-my"). The currency format display as R. But if I look at the watcher on my local console code nothing related to the server, it's set to RM

Application changes not taking effect

I have made a change to a method used in a Functiod in a mapping file but it seems the new code is not taking effect, ever.
I have deployed properly, started the application, restarted related host instance (actually all host instances I could find) and still, the old code seems to execute.
Here's the, simple, method:
public string RemoveNonNumericChars(string stIn, int maxLength)
{
string strOut;
try
{
strOut = Regex.Replace(stIn, "[^0-9]", "");
System.Diagnostics.EventLog.WriteEntry("BizTalk Server 2009", strOut);
return strOut.Substring(0, maxLength);
}
catch
{
return string.Empty;
}
}
I added the writing to EventLog line to see that this code is indeed being executed, but I don't get anything in "Application" event logs.
I do NOT get an empty string being returned, so it really does seem like the old code that's being executed prior to me fixing the method.
What am I missing exactly ?
Thank you.
For some reason, the script is not able to correctly retrieve the Build Config selected in Visual Studio, it's taken from Debug when I'm actually trying to build it for a Test environment. I should have known, thanks anyways.

Reset settings to SpecialFolder

I store the directory path of a folder in Properties.Settings.Default.Temporary and I allow the user to change this value and other settings using a PropertyGrid.
When the user decides to reset the Settings, I would like to change Properties.Settings.Default.Temporary to the value of System.IO.Path.GetTempPath() by using Properties.Settings.Default.Reset()
I know about System.Configuration.DefaultSettingValueAttribute. Something like this:
[global::System.Configuration.DefaultSettingValueAttribute(System.IO.Path.GetTempPath())]
does not work.
I also read Storing default value in Application settings (C#), which described a related problem, but I wonder if there is a way to solve my problem in the way described above.
The DefaultSettingValueAttribute.Value property is a string, therefore you cannot pass a function call to be called when the value is used. In fact there is no ability to pass code to an attribute: only literals are possible.
Instead in your applications code where you reset the settings, follow this by setting and settings that you want to have values that are not literals at compile time (eg. dependent on the execution environment).
I just had an idea for a workaround myself:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute(null)]
public string TemporaryDirectory
{
get
{
if (this["TemporaryDirectory"] == null)
{
return System.IO.Path.GetTempPath();
}
return ((string)this["TemporaryDirectory"]);
}
set
{
if (System.IO.Directory.Exists(value) == false)
{
throw new System.IO.DirectoryNotFoundException("Directory does not exist.");
}
this["TemporaryDirectory"] = value;
}
}
I don't know, if this has any side effects, but so far it seems to work. I am sorry that I had this idea shortly after posting. I should've thought about the problem a bit longer.

Strange error when using "Double.NaN" and "double.MaxValue" in c#

I have a function in my code like (C#, NET 3.5, Visual Studio 2008):
public double function CalculateSomething()
{
...
double a = double.NaN; // Or double.MaxValue, with same behaviour
...
}
This function is called by the main class, like this:
...
double res = o.CalculateSomething();
...
Although it looks like incredible (for me, it is) and ONLY on certain computers (only in 2 computers from 60) without anything special (WinXP SP3), if I use the "alias" (double.NaN or double.MaxValue) the program is broken without any kind of error screen when the program calls "CalculateSomething", whereas if you assign a particular value, works perfectly.
I mean:
public double function CalculateSomething()
{
...
double a = double.NaN; // FAAAAIL!!!!
double b = -99999; // OK...
...
}
Although the change I made, the program can run on all computers, i have curiosity. Does anyone know what may be happening?. Thank you.
Ok, i found the problem:
I installed NET 4.0, but the program needed NET 3.5. I installed NET 3.5 and it worked.
Really, that rarest thing, i have ever seen.
Thank you all for your responses.

Categories

Resources