If your application needs to support only a specific format (or culture), you could specify it in your Configure method as follows:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var cultureInfo = new CultureInfo("en-US");
cultureInfo.NumberFormat.NumberGroupSeparator = ",";
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
[...]
}
If you want to support several cultures and to automatically select the right one for each request, you can use the localization middleware instead, e.g.:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
[...]
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es"),
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
// Formatting numbers, dates, etc.
SupportedCultures = supportedCultures,
// Localized UI strings.
SupportedUICultures = supportedCultures
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
More info here: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.2
Edit - Decimal binder
If everything above fails, you could also roll your own model binder, e.g.:
public class CustomBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(decimal))
{
return new DecimalModelBinder();
}
return null;
}
}
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;
}
// Remove unnecessary commas and spaces
value = value.Replace(",", string.Empty).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;
}
}
Don't forget to register the custom binder in your ConfigureServices method:
services.AddMvc((options) =>
{
options.ModelBinderProviders.Insert(0, new CustomBinderProvider());
});
Now every time you use a decimal type in any of your models, it will be parsed by your custom binder.