asp.net core 2.0 bind model with decimal value

时光总嘲笑我的痴心妄想 提交于 2020-12-05 11:14:35

问题


I've been looking for a solution to this case for hours, and I did not find anything that worked out for me.

Here we use the comma for decimal separator, and when I send a value like "15,50", in my controller I get the value of the model as "1550", and it only makes sense if I send "15.50".

I covered the following topics, and nothing worked.

Set CultureInfo in Asp.net Core to have a . as CurrencyDecimalSeparator instead of ,

Aspnet Core Decimal binding not working on non English Culture

I am sending the form with ajax, using the $form.serializeArray() as below:

function getFormData(xform) {
    var $form = $('#' + xform);
    var unindexed_array = $form.serializeArray();
    var indexed_array = {};

    $.map(unindexed_array, function (n, i) {
        indexed_array[n['name']] = n['value'];
    });    
    return indexed_array;
}

send:

function PostFormAjax(controller, metodo, params, redir, divacao, reloadgrid) {

    if (params != null) {
        var formData = new FormData();

        var json = $.parseJSON(JSON.stringify(params));
        $(json).each(function (i, val) {
            $.each(val, function (k, v) {
                console.log(k + " : " + v);
                formData.append(k, v);
            });
        });
    }

    $.ajax({
        url: '/' + controller + '/' + metodo,
        data: JSON.stringify(params),
        contentType: 'application/json',
        type: 'POST',
        success: function (data) {
            AjaxFim(metodo, data, redir, divacao, reloadgrid);
        }
    });
}

My controller:

    [HttpPost]
    public IActionResult GravaProduto([FromBody] Produtos produto)
    {
        if (ModelState.IsValid)
        {
         //produto.Valorcusto is 1550 and not 15,50 as it was posted
         //produto.Valorvenda is 1550 and not 15,50 as it was posted
        }
    }

My Model.cs

public partial class Produtos
{
    public int Cod { get; set; }
    public string Descricao { get; set; }
    public decimal Valorcusto { get; set; }
    public decimal Valorvenda { get; set; }
}

I tried to make a replace in formData.append(k, v.replace(',', '.')); and also does not work, I also would not know which field is a decimal.

What do I have to do? because I'm lost, what should have been simpler became more complicated.

What I did to keep working until I found a solution was:

Wear a mask according to my regional setting:

$('.stValor').mask("#.###.##0,00", { reverse: true });

And before posting the form, I switch to the accepted formatting:

$('#fCadAltProd').validator().on('submit', function (e) {
    if (e.isDefaultPrevented()) {
    } else {
        e.preventDefault();
        $('.stValor').mask("#,###,##0.00", { reverse: true });
        //Ajax post here
    }
});

回答1:


Use this plugin jquery.serializeToJSON and change your getFormData() function to

function getFormData(xform) {
    var $form = $('#' + xform);
    var obj = $form.serializeToJSON({
        parseFloat: {
            condition: ".stValor,.stQnt,.stDesconto",
            nanToZero: true,
            getInputValue: function (i) {
                return i.val().split(".").join("").replace(",", "."); 
            }
        }
    });
    return obj;
}

parseFloat.getInputValue: function(){}, By default, returns the input value without commas, not an error occurs in conversion. if your location uses comma for decimal separation, for example in German or Brazil, you can change to

function(i){ 
    return i.val().split(".").join("").replace(",", "."); 
}

This will do all the work for you.




回答2:


Here we use the comma for decimal separator, and when I send a value like "15,50", in my controller I get the value of the model as "1550", and it only makes sense if I send "15.50".

Create a custom model binder using the Norwegian culture, because Norway also uses the comma decimal separator. You might also want to specify certain multiple allowed number styles.

Here is one that still needs to have error handling. It gives you the basic idea, though, and you can build on it from here. What I would do it copy most of the logic from the built-in DecimalModelBinder.

using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging;

namespace AspNetCorePlayground.Models
{
    public class MyFirstModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var valueProviderResult = bindingContext
                .ValueProvider
                .GetValue(bindingContext.ModelName);

            var cultureInfo = new CultureInfo("no"); // Norwegian

            decimal.TryParse(
                valueProviderResult.FirstValue,
                // add more NumberStyles as necessary
                NumberStyles.AllowDecimalPoint, 
                cultureInfo,
                out var model);

            bindingContext
                .ModelState
                .SetModelValue(bindingContext.ModelName, valueProviderResult);

            bindingContext.Result = ModelBindingResult.Success(model);    
            return Task.CompletedTask;
        }
    }
}

Then decorate your class like this:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;

namespace AspNetCorePlayground.Models
{
    public class MyFirstModelBinderTest
    {
        [ModelBinder(BinderType = typeof(MyFirstModelBinder))]
        public decimal SomeDecimal { get; set; }
    }
}

I tested it on a controller:

[HttpGet("test")]
public IActionResult TestMyFirstModelBinder(MyFirstModelBinderTest model)
{
    return Json(model);
}

This is the result:



来源:https://stackoverflow.com/questions/50977542/asp-net-core-2-0-bind-model-with-decimal-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!