Hi everyone. I have an aspnet core app that runs with a non english configuration (spanish):
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory
{
......
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(new CultureInfo("es-AR"))
,SupportedCultures = new List<CultureInfo>
{
new CultureInfo("es-AR")
}
,SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("es")
}
});
.........
}
In english a decimal number has its decimal part delimited with a dot, but in spanish a comma is used:
I have this action in a controller:
[HttpPost]
public decimal Test(decimal val)
{
return val;
}
If I use postman and send to that action a json like this {val: 15.30}, then val in the action recives a 0 (binding not working because of the culture). If I send a json like this {val: 15,30} then in the action I recive 15.30
The problem I have is, I need the action to accept decimals with commas, because that is the format that comes from inputs type text in the app's forms. But i also need to accept decimal with a dot that comes from request in json format. There is no way to specify a decimal/float in json that accepts a comma (send it as string is not an option). How can I do this??? I'm driving my self crazy with this.
Thanks!!
Could we see a bit more of your app? In particular
app.UseRequestLocalization() call before or after app.UseMvc()?[FromBody] i.e. public decimal Test([FromBody] decimal val)?Here is what you asked me:
This is the configure method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug(LogLevel.Trace);
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(new CultureInfo("es-AR"))
,SupportedCultures = new List<CultureInfo>
{
new CultureInfo("es-AR")
}
,SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("es")
}
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Site/Error");
}
app.UseStaticFiles();
app.UseAppAuthentication(Configuration);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areaRoute",
template: "{area:exists}/{controller=Site}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Site}/{action=Index}/{id?}");
});
}
I don't use [FromBody] anywhere, should I? all my POST actions look like this:
[HttpPost]
public CLASS ACTION_NAME(TYPE OBJECT)
{
return XXXX;
}
Example:
[HttpPost]
public decimal prueba(decimal val)
{
return val;
}
How can I accept numbers in json format in my culture that does not accept numbers in that format?
I've used [FromBody] and still the same result. It only accepts decimals with comma.
[HttpPost]
public decimal prueba([FromBody] decimal val)
{
return val;
}
This is the request the app accepts:
This is the request the app does not accept:
I need the app to accept both on my current culture (es-AR). When the data comes from a html form, it comes already formatted with comma. When I send it through json it must accept the dot as a decimal separator.
I'm not sure how your application is working w/o [FromBody].
You need to make a change in the JsonSerializerSettings when you are using [FromBody]. It's a slight Json.NET reconfiguration: The default JsonSerializerSettings.Culture is CultureInfo.InvariantCulture and that controls the "culture used when reading JSON".
Suggest the following in your Startup.ConfigureServices() method:
c#
services
.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.Culture = CultureInfo.CurrentCulture);
that's a really surprising default :disappointed:
Still does not work. It doesn't accept numbers with dot due the current culture. What is failing is the model binder.
You mentioned JSON earlier - but your example screenshots show x-www-form-urlencoded
I re-read your first post, and it sounds like what you need is two different actions.
MVC core does not treat JSON and form-data as the same. [FromBody] is used for JSON and _normal_ model binding handles form-data.
I'd try something like this:
[HttpPost]
[ActionName("prueba")]
[Consumes("application/x-www-url-formencoded")]
public decimal TestForm(decimal val)
{
return val;
}
[HttpPost]
[ActionName("prueba")]
[Consumes("application/json")]
public decimal TestJson([FromBody] TestModel val)
{
return val;
}
public class TestModel
{
public decimal Val { get; set; }
}
[Consumes] will dispatch to the correct action based on the the content type of the submitted request. You could also use different URLs/action-names if you'd prefer.
I think the issues that you're seeing with the JSON aren't related to the culture - it's actually that the object submitted in JSON is { val = 3.14 }, and object with the property val. You need to use a class that matches.
You could alternative use JObject in your _JSON_ action if you want a dynamic view of the data.
With all of that said, tread very carefully if you're trying to expose the same functionality over JSON and HTML form. The primary reason why we separated these is that there are a number of concerns that you will want to handle separate (mostly security-related) for an HTML form, an ajax client or a 3rd part arbitrary HTTP client.
If this is intended to be used by a browser, you'll also need antiforgery/CSRF protection for any reason site.
@dougbu @rynowak the JSON RFC specifies that the decimal point should be used:
A fraction part is a decimal point followed by one or more digits.
Changing the culture of the JSON serializer settings as suggested is likely to reduce interoperability.
OK than that makes more sense about why InvariantCulture is the default, I stand corrected.
@rynowak I tested it. Using:
[Consumes("application/x-www-url-formencoded")] : accepts number with comma, but not number with dot[Consumes("application/json")]: accepts numbers with dot, but not number with comma.Honestly i didn麓t know the use of [FromBody], now i know.
Where is my problem? I have certain type of functionality where I send a post to the server using jquery like this:
$.ajax({
url: '..........................',
type: 'post',
data: $form.serialize() + '&' + $.param(data),
dataType: 'json'
})
data is a json array of objects, and the form is a standard form. I'm sending a form and an array of json to an action. In the form I have numbers with comma and in the array I have numbers with dot. So when the request goes to the action, the binding only happens with the numbers with comma, and the numbers with dot are not binded. The problem I see now with your explanation is that I'm mixing the the form and json data in one action. Right now it can't be all data from a form or all the data in json, it is mixing both. Is there any way to accept the data the way I'm sending it. Meanwhile I solved it with a custom model binder that reads both, number with comma and number with dot as a valid decimal, but I don't want to do that.
Did I explained the problem or it is still unclear? Thanks a lot for your help.
A custom model binder is about the only way to handle either decimal format in a JSON submission.
I'm not sure how your application is working w/o
[FromBody].You need to make a change in the
JsonSerializerSettingswhen you are using[FromBody]. It's a slight Json.NET reconfiguration: The defaultJsonSerializerSettings.CultureisCultureInfo.InvariantCultureand that controls the "culture used when reading JSON".Suggest the following in your
Startup.ConfigureServices()method:services .AddMvc() .AddJsonOptions(options => options.SerializerSettings.Culture = CultureInfo.CurrentCulture);
It has worked for me. Thank you @dougbu