Reputation: 489
I have a REST API in .Net Core 3 and front end in Angular 8. My front is a multilingual admin panel where I need to configure price for a product. The issue is I am not able receive price with decimal values.
My default culture of .NET Core API is "en-US" but my client is using "nl-NL" from front end. As you know Netherland they use "," instead of "." for decimal points therefore I am not getting price in my submitted model. Here are code snippets;
REST API
Entity
public class Product{
public Guid Id {get;set;}
public string Name {get;set;}
public decimal Price {get;set;}
}
Controller Method
[HttpPost]
public Task<IActionResult> SaveProduct([FromForm]Product model){
....code to save the product....
}
Stratup.cs
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("en"),
new CultureInfo("de"),
new CultureInfo("fr"),
new CultureInfo("sv")
};
options.RequestCultureProviders = new List<IRequestCultureProvider>()
{
new AcceptLanguageHeaderRequestCultureProvider()
};
options.FallBackToParentCultures = true;
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
I tried setting Requestdefault culture to "nl" but then "en" values doesn't work. Can any one please help me how to pass decimal points from multilingual frontend to a REST API.
Thanks.
Upvotes: 0
Views: 5158
Reputation: 9804
Getting Decimal values for a price from the client is a terrible idea. I remember stories where a haphazard developer had put the shopping cart into the cookie, including prices. It took not that long for this mistake to be found and exploited. The company had the bill, because they had made their shop faulty.
Never trust input from the user. Especially if that user is on the Internet.
As for the specific problem: You basically have the issue that frontend and backend culture varies. I got 3 items of advice for transmitting numbers between processes:
Upvotes: 0
Reputation: 20116
If you use [FromForm]
,you could create your own custom mobel binder for the Price
property:
1.Create a DecimalModelBinder
public class DecimalModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null)
{
return Task.CompletedTask;
}
var value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
// Replace commas and remove spaces
value = value.Replace(",", ".").Trim();
decimal myValue = 0;
if (!decimal.TryParse(value, out myValue))
{
// Error
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
"Could not parse MyValue.");
return Task.CompletedTask;
}
bindingContext.Result = ModelBindingResult.Success(myValue);
return Task.CompletedTask;
}
}
2.Use it on Price
property
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; }
[BindProperty(BinderType = typeof(DecimalModelBinder))]
public decimal Price { get; set; }
}
3.Action
[HttpPost]
public Task<IActionResult> SaveProduct([FromForm]Product model){
....code to save the product....
}
Upvotes: 1
Reputation: 10538
Based on your question, it appears that your problem is that your front-end code is submitting the price with a comma on it. This can only be possible if you are sending a string representation of the price to the server, rather than a numeric one.
You should modify your front end code to always store and transmit the price value as a number
. You can control how a price is displayed to a user in strings using Intl.NumberFormat()
.
As the user has to enter a price, you're probably using a <input type=text />
tag to capture the cost of the product. Since we want users to be able to enter commas here, we can't use <input type=number />
- instead, we can simply modify the value we get from this input tag on the client side by replacing occurences of commas in the string with a period - amount.replace(',', '.')
- and then attempting to parse the number from the string - parseInt(amount, 10)
.
If parseInt
returns NaN
, you should display a validation error to the user.
Upvotes: 0