2

If I open up a Console Application and run this:

decimal urmom = 84.3400m;
Console.WriteLine(urmom.ToString("F02"));

I get 84.34

In a web application I'm running, I have this code:

public static string PayPalJunk(string successURL, string failureURL, decimal total, string currency)
{
    NVPCodec encoder = new NVPCodec();
    encoder["PAYMENTREQUEST_0_AMT"] = total.ToString("F02");
    //...
}

Even if I break before executing that line and do a Watch on total.ToString("F02"), i get 84,34. The Mouseover of total in the parameter list shows 84.34.

Why? decimal is just a value, right? It isn't a reference object with some hidden properties that might have been corrupted with some culture info... right?

Suamere
  • 5,691
  • 2
  • 44
  • 58
  • 2
    What is the default culture of the web server? – DavidG Sep 20 '16 at 15:51
  • _"Why?"_ -- "why" what? `decimal` is "just a value", yes. But unless you read binary decimal formats, the only time you'll ever _see_ a `decimal` value, it will have been converted from its actual value to text, and that conversion depends on the environment in which the conversion is performed. The `ToString()` method, by default, uses the environment's culture, and you'll get different results when the environment's culture is different. So, what's your question? Your debugger shows you the value using your debugger's environment's settings, and the web server shows the value using its. – Peter Duniho Sep 20 '16 at 16:26
  • For related discussion, see https://stackoverflow.com/questions/30889114/c-sharp-decimal-tostring-conversion-with-comma, https://stackoverflow.com/questions/33552847/change-display-format-number-decimal-separator, and the many other similar questions on Stack Overflow. – Peter Duniho Sep 20 '16 at 16:26

2 Answers2

1

It has to do with the culture of the thread that is running. If you want to get the string formatted in en-US regardless of the thread then you need to pass in a specific culture to ToString. If its running under a web server and you want to ignore the culture of the requsting browser/client you can also specify a static culture in the web.config.

How to specify culture in ToString

var formatted1 = total.ToString("F02", System.Globalization.CultureInfo.InvariantCulture);
// or
var formatted2 = total.ToString("F02", new System.Globalization.CultureInfo("en-US"));

See Decimal.ToString Method (String,IFormatProvider)

How to configure web.config

<globalization uiCulture="en" culture="en-US" />

See also How to: Set the Culture and UI Culture for ASP.NET Web Page Globalization


Why? decimal is just a value, right?

No, you are converting the decimal to a string and depending on the culture that string representing the decimal might be displayed differently. For example: in the Netherlands a comma is used to separate a whole value from the partial/fractional part of the value and a period (.) is used to segregate groupings like thousands,millions,billions,trillians etc. In the USA these symbols have the exact opposite meaning.

Detecting the culture of the caller is usually a good thing and returning the data formatted based on the callers culture is usually also desired behavior. If not though then see above for 2 ways to ensure that the code can always return a consistent formatted data.

Igor
  • 60,821
  • 10
  • 100
  • 175
  • Thanks Igor. You point out the one thing I was missing. `decimal` is not culture-specific, but ToString() is. I was already altering the culture to force en-US, but the mystery was killing me. Turns out, somebody recently added `System.Threading.Thread.CurrentThread.CurrentUICulture`. Wheeeee – Suamere Sep 20 '16 at 16:31
0

You are getting these results because the cultures in two environments are different. Try this:

encoder["PAYMENTREQUEST_0_AMT"] = total.ToString("F02", System.Globalization.CultureInfo.InvariantCulture);

or whatever culture you want your string formatted to.

Trifon
  • 1,081
  • 9
  • 19