【问题标题】:asp.net core 2.0 bind model with decimal valueasp.net core 2.0 用十进制值绑定模型
【发布时间】:2018-06-21 21:15:35
【问题描述】:

几个小时以来,我一直在寻找这个案例的解决方案,但没有找到任何适合我的方法。

这里我们使用逗号作为小数分隔符,当我发送一个像“15,50”这样的值时,在我的控制器中我得到的模型值是“1550”,只有发送“15.50”才有意义”。

我涵盖了以下主题,但没有任何效果。

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

Aspnet Core Decimal binding not working on non English Culture

我使用 ajax 发送表单,使用 $form.serializeArray() 如下:

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;
}

发送:

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);
        }
    });
}

我的控制器:

    [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
        }
    }

我的模型.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; }
}

我尝试在 formData.append(k, v.replace(',', '.')); 中进行替换,但也不起作用,我也不知道哪个字段是小数。

我该怎么办?因为迷路了,本来应该简单的事情变得复杂了。

在找到解决方案之前,我一直在努力:

根据我的地区设置戴口罩:

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

在发布表单之前,我切换到接受的格式:

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

【问题讨论】:

  • 只需编写一个自定义模型绑定器,而不是使用文化信息将字符串值解析为小数,请参阅article
  • 离题,但你可以pass a form element to the FormData constructor,它会自动填充你所有的表单元素。
  • 如果值为“15,50”,formData.append(k, v.replace(',', '.')) 应该可以工作。如果值为1.150,50,我可以看到它不起作用,因为您还必须用, 替换.,也许用v.replace(/[,.]/g, (c) => c == "." ? "," : ".") 之类的东西。
  • 您可能想查看this answer to How can I parse a string with a comma thousand separator to a number?。您仍然需要确定哪些是数字,但这可以通过像 /^[\d,.]+$/ 这样的简单正则表达式来完成。

标签: c# asp.net-mvc entity-framework asp.net-core


【解决方案1】:

这里我们使用逗号作为小数分隔符,当我发送一个像“15,50”这样的值时,在我的控制器中我得到的模型值是“1550”,只有发送“15.50”才有意义”。

使用the Norwegian culture 创建custom model binder,因为挪威也使用逗号小数分隔符。您可能还想指定某些multiple allowed number styles

这里仍然需要进行错误处理。但是,它为您提供了基本概念,您可以从这里开始构建它。我会从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;
        }
    }
}

然后像这样装饰你的班级:

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; }
    }
}

我在控制器上测试过:

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

这是结果:

【讨论】:

  • 也没用,我通过ajax传帖子,得到完整的模板
  • 我没有通过 get 测试,在我的项目中实现,并且帖子一直没有小数分隔符,没有“。”或“,”
  • 听起来您只在寻找 HTTP POST 支持而不是 HTTP GET 支持。对吗?
  • 是的,我需要使用 HTTP POST 和 AJAX 发送表单。
【解决方案2】:

使用这个插件jquery.serializeToJSON 并将您的 getFormData() 函数更改为

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(){},默认返回不带逗号的输入值,转换不会出错。如果您的位置使用逗号分隔小数点,例如在德语或巴西,您可以更改为

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

这将为您完成所有工作。

【讨论】:

  • 这绝对是个坏办法
猜你喜欢
  • 2023-03-25
  • 2011-08-07
  • 1970-01-01
  • 2013-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-19
  • 1970-01-01
相关资源
最近更新 更多