In my MVC app, I made this simple test function...
Function test(d As Decimal) As JsonResult
Return Json(d)
End Function
Sending .../?d=1900 works fine.
Sending .../?d=1,900 fails with "d" being null.
Sending .../?d=1.900 converts d to 1.9D <--- I NEED THIS ONE
Since I'm danish, I want to be able to pass 1.900 to "d" so it will be one-thousand-nine-hundred.
I tried setting this in web.config...
...that din't help.
Any idea?
What you need to be doing here is doing a culture-specific conversion to decimal. If you don't specify a culture, ASP.NET MVC will use the Invariant Culture. Similarly, if you use the decimal.Parse function without a culture will use the system's current culture.
What you need to do is use the function Decimal.Parse with a culture that you supply. see here
You could set each user's culture up in whatever user/session sort of setup you have, or you could pass it in as a parameter. E.g:
/?d=1,900&culture=da-DK
Then you might pass
decimal.Parse(d, System.Globalization.CultureInfo.GetCultureInfo(culture))
Related
I have an MVC Web-API application for inner use. I have some pages with forms and numeric fields. I need to install this on a German computer, and the users will be only Germans. In Germany they write "3,5" instead of "3.5" (with a comma).
In IIS configuration the culture is "Invariant culture" and since the computer is German - the localize is "de-DE".
When the users write "3,5" in the field - I can see in firebug that "3,5" is what is sent in JSON, but the server gets it as "35".
Can I handle it on server-side? (I don't want to change the json because I'll need to do it in every field and page)
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public class ItemsController : ApiController, IDisposable
{
[Authorize(Roles = "Admin")]
[HttpPost]
public HttpResponseMessage UpdateItem(ItemViewModel itemVM)
{
// JSON data sent data.NumProp1 = "3,5"
// itemVM.NumProp1 contains "35" instead of "3.5"
}
}
You should not localize your JSON - see http://www.json.org for the spec (which only shows the dot as a separator) and How to localize when JSON-serializing? for a similar question.
I wouldn't recommend trying to read your customized JSON - it may sound like a quick win right now, but in the end you simply aren't using JSON.
You must use CultureInfo.InvariantCulture on all your string formating calls when handling persitence (and JSON exchanges are technically a form of persitence):
Persisting Data
The InvariantCulture property can be used to persist data in a
culture-independent format. This provides a known format that does not
change and that can be used to serialize and deserialize data across
cultures. After the data is deserialized, it can be formatted
appropriately based on the cultural conventions of the current user.
For example, if you choose to persist date and time data in string
form, you can pass the InvariantCulture object to the
DateTime.ToString(String, IFormatProvider) or
DateTimeOffset.ToString(IFormatProvider) method to create the string,
and you can pass the InvariantCulture object to the
DateTime.Parse(String, IFormatProvider) or
DateTimeOffset.Parse(String, IFormatProvider, DateTimeStyles) method
to convert the string back to a date and time value. This technique
ensures that the underlying date and time values do not change when
the data is read or written by users from different cultures.
This applies to all types: numerics, decimals, floats and doubles, date and time etc. Use the invariant culture both when writing and when reading serialized data. Use invariant culture on both sides of a JSON exchange.
BTW, if you'd use the built-in JSON serializers, you'd already get this lunch for free: JsonWriter.cs, JsonReader.cs.
As already said: JSON is a standard, and you should never deviate from the standard. Doing that will make your life miserable.
If the users enter some numbers in a web form, that web form should serialize that in the correct JSON format. I think usually that is done already, if you use the right numeric types in your form, like input type='number', etc. On the server end, you should read it using the InvariantCulture.
This need for a general solution is acknowledged by the W3C, as you can see in the draft W3C HTML JSON form submission.
In addition to the other answers, if you want to just replace the German "," decimal separator with the current culture one, which makes the conversion parse correctly, use:
str = str.Replace(",", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
You can then convert your string into a numeric value using stuff like Convert.ToInt32
I have a problem with converting string to double, it works fine when I run it on my local machine but when I deploy it to the server it "cuts" 0 in front.
For example I have a string value of 0,0123 and when I convert it to double I get 123.
I use ASP.NET with C#, method I use is Convert.ToDouble() and the hosting is somee.com.
Right now I just divide the number by 10000 and get what I need, but as you can imagine it's not prefect solution so maybe someone has better idea of how to solve it.
This happens because your machine and the server are using two different cultures.
Some cultures use "." as a decimal point, while others use ",".
It seems that in your server culture, "." is the decimal point - and so the comma in "0,0123" is treated as a thousands separator instead.
I would use the overload for double.TryParse or Convert.ToDouble that takes an IFormatProvider and pass in the correct CultureInfo.
In the future, try using CultureInfo.InvariantCulture to format all your internal data (i.e. data persistence, or data flowing within your system), and use the proper CultureInfo for displaying data to the user.
The decimal point is not the same across cultures and, therefore, computers with different culture setting.
Try using double.Parse(string, CultureInfo) with an explicit CultureInfo that works for your format.
Based on the fact you express your value as 0,0123 rather than 0.0123, I would guess the language/culture settings on the server are different than on your own machine.
Try printing out the result of System.Globalization.CultureInfo.CurrentCulture.Name from somewhere on the server, and compare it to what your local machine produces.
I need to format the Decimal variables Latitude=9113267; Longitude=59300357;
to string format 9,113267 and 59,300357
Thx
john
VascoP is right in how to convert the number to a "proper" decimal but he is wrong about how to convert those decimal values to a string. the ToString method has an overload whose signature is
public string ToString(IFormatProvider provider)
See: http://msdn.microsoft.com/en-us/library/3ebe5aks.aspx
You can use this to create a culture specific string. The examples on the linked page show how to do it but for completeness of answer an example might be:
(Latitude/1000000).ToString(CultureInfo.CreateSpecificCulture("en-GB") // Outputs with a "." decimal separator
(Latitude/1000000).ToString(CultureInfo.CreateSpecificCulture("de-DE") // Outputs with a "," decimal separator
I assume you have a specific culture that you want to be able to understand this so you should use the correct culture. That makes it much easier to change later if you want (eg you can pick up the culture from a global config setting) or have a user preference for the number format, etc.
Also if you start using custom formats (eg to put thousand separators in) then the cultureinfo object will again do the right thing.
It should also be noted at the end of all this that you may just need the .ToString if the default culture is actually the one you are using. You didn't provide that info though so I just assumed that a simple ToString wouldn't be doing the trick.
(Latitude/1000000).ToString().Replace('.', ',');
(Longitude/1000000).ToString().Replace('.', ',');
EDIT: Although this works, as stated by Chris, it is not best practice. You should use his solution instead.
When I try to convert a string to float:
Console.WriteLine(float.Parse("6.59"));
it throws an exception:
Unhandled Exception: System.FormatException: Input string was not in a correct f
ormat.
at System.Number.ParseSingle(String value, NumberStyles options, NumberFormat
Info numfmt)
When I try it like this:
Console.WriteLine(Convert.ToSingle("6.59"));
It throws the same exception:
Unhandled Exception: System.FormatException: Input string was not in a correct f
ormat.
at System.Number.ParseSingle(String value, NumberStyles options, NumberFormat
Info numfmt)
at System.Convert.ToSingle(String value)
Can you explain why this happens?
The single argument Parse method uses the current culture to parse the string. If your current culture uses some other decimal separator, this will fail.
Try using the invariant culture:
float.Parse("6.59", CultureInfo.InvariantCulture)
The problem here is your culture.
Either set the invariant culture like this:
float.Parse("6.59", CultureInfo.InvariantCulture)
or use the correct decimal separator for your culture
float.Parse("6,59")
I wonder why you are using a literal string. If you are having problems entering literal floats, you can use
Console.WriteLine(6.59f)
If you do it this way culture doesn't matter because the value is decided at compile time.
You are probably using a culture that uses the , as a decimal seperator.
You could try to Parse using the InvariantCulture:
float.Parse("6.59", CultureInfo.InvariantCulture)
Culture - specific things. What's your default culture?
Some cultures use "," instead of ".". You can try this:
float.Parse("6.59", CultureInfo.InvariantCulture);
There could be problem with Locale/Culture. You need to set , instead of . for the decimal separator.
I know everyone here has already given the reason for the problem experienced but perhaps somebody should just expand on why Invariant fixes it.
The CultureInfo class is used either directly or indirectly by classes that format, parse, or manipulate culture-specific data, such as String, DateTime, DateTimeOffset, and the numeric types to deal with the differences in the way different cultures write these types.
In case of the decimal type some cultures use a period(.) whilst others use a comma (,). By default when you are using the Conversion Libraries it will make use of your local culture (that is the country your OS to configured for).
By specifying Invariant you say that you expect thousand separators to be commas(,) and decimal deliminator to be a period(.) as it is in most cultures.
A big problem that sometimes happens is that these cultural conventions change from the OS point of view. For example the South African (ZA) culture info used to behave like the invariant culture. Microsoft changed this with Windows 8 where the decimal suddenly became a comma and the thousand separator a space.This resulted in many legacy systems written in .Net suddently breaking when one migrated them to newer operating systems.
In the end, deal normalize all local culture info to invariant and persist and deal with them in your business logic in this format. Then localize it back on the front end. Same goes for DateTime, as soon as possible convert to UTC, and only back when you render an output.
You could also try Convert class to perform this task.
Convert.ToDecimal("6.59");
I have a textbox accepting user input; I am trying to use this user input it to populate this member of one of my business objects:
public System.Decimal? ExchangeRate
The application is localized - I need to support at the same time cultures that accept these as valid inputs: "1,5" and "1.5"
The code I have now is:
var culture = Thread.CurrentThread.CurrentUICulture;
int exchangeRate;
int.TryParse(txtExchangeRate.Text, NumberStyles.Number, culture,
out exchangeRate);
entity.ExchangeRate = exchangeRate;
When the user culture is set to a culture that expects the "1,5" format (comma as decimal separator) - e.g "ro-RO", I want the value that gets stored in entity.ExchangeRate to be 1.5; however, when running the code above, it gets converted to 15 instead.
Any suggestions on how to convert these various formats so that the data that gets stored in my business entity is "1.5" (point as decimal separator)?
Thanks.
You guys were right - it made sense to use Thread.CurrentThread.CurrentCulture instead of Thread.CurrentThread.CurrentUICulture and decimal.TryParse instead of int.TryParse.
But these changes would still not solve my problem. And after playing around with the code some more, I can now simplify the issue to this:
I am using a telerik RadNumericTextBox control which enforce users to use the correct format based on their culture. So, when Thread.CurrentThread.CurrentCulture is set to "ro-RO", it will only accept the "1,5" format, and when it's set to "en-GB", it will only accept the "1.5" format.
Here's the code I am using now:
decimal exchangeRate;
decimal.TryParse(txtExchangeRate.Text, out exchangeRate);
entity.ExchangeRate = exchangeRate;
Case 1: current culture is "en-GB" - accepted input is "1.5" , exchangeRate is set to 1.5 - everything works fine.
Case 2: current culture is "ro-RO" - accepted input is "1,5" , but after executing the decimal.TryParse... line, exchangeRate is set to 15 - wrong, obviously.
I should also mention that in this case, the value of txtExchangeRate.Text is also shown as "1.5" in my Watch window.
So, it looks like decimal.TryParse will take into consideration the current culture, but I can't find a way to actually make it work properly for me. Any suggestions?
OK, here's the code that seems to work on both cases I described in my above post (1. culture "ro-RO", comma as decimal separator and 2. culture "en-GB", dot as decimal separator):
decimal exchangeRate;
decimal.TryParse(txtExchangeRate.Text, NumberStyles.Any,
CultureInfo.InvariantCulture, out exchangeRate);
entity.ExchangeRate = exchangeRate;
Obviously, int cannot hold 1.5 ! :-) Use float instead.
Use CurrentCulture instead of CurrentUICulture. My culture is fr-BE (therefore accepts 1,5 but my Windows UI is English, which doesn't).
I would make the float.Parse() test with both CurrentCulture AND InvariantCulture: By the time some programs learned to accept "1,5", everybody was used to type "1.5". There's nothing which bothers me more than Excel requiring me to type 1,5 when I say 1.5 ! Also, here in Belgium, the 1st year government launched the web-based tax declaration, the site forced you to use commas instead of periods as decimal points. Everybody was wondering why the figures entered were refused!
So be nice to your users and accept both.
FYI I know this isn't your problem, but its a pointer for other people who might be doing this:
When you set your culture, you can't have your application be able to handle input of different cultures. It must be of the type that you have specified.
Therefore, if you set ro-RO as the culture, it won't understand both 1.5 and 1,5 as the same thing.
You should probably be using CurrentCulture (as opposed to CurrentUICulture) for localization (e.g. date/number formatting).