ASP.NET MVC 3默认模型绑定器无法绑定decimal属性

47

由于某些原因,当我将这个JSON发送到一个操作时:

{"BaseLoanAmount": 5000}

这个属性应该绑定到一个名为“BaseLoanAmount”的十进制数属性的模型上,但它没有绑定,仍然保持为0。但是,如果我发送:

{"BaseLoanAmount": 5000.00}

它确实绑定了属性,但为什么呢?即使它没有小数,难道5000不能被转换为十进制吗?

2个回答

75

进入asp.net mvc源代码后,看起来问题在于转换时使用了框架的类型转换器,但由于某些原因,int到decimal的转换会返回false。最终我使用了自定义模型绑定提供程序和模型绑定器来处理decimal类型,你可以在这里看到:

public class DecimalModelBinder : DefaultModelBinder
{
    #region Implementation of IModelBinder

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if (valueProviderResult.AttemptedValue.Equals("N.aN") ||
            valueProviderResult.AttemptedValue.Equals("NaN") ||
            valueProviderResult.AttemptedValue.Equals("Infini.ty") ||
            valueProviderResult.AttemptedValue.Equals("Infinity") ||
            string.IsNullOrEmpty(valueProviderResult.AttemptedValue))
            return 0m;

       return Convert.ToDecimal(valueProviderResult.AttemptedValue);
    }    

    #endregion
}

为了注册此 ModelBinder,只需在 Application_Start() 函数中添加以下代码:

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());

4
return语句中的布尔表达式valueProviderResult==null不能评估为真,因为在之前,valueProviderResult.AttemptedValue会抛出一个空引用异常。为了让内容更加通俗易懂,可以将其翻译为:“由于在valueProviderResult.AttemptedValue之前可能会出现空引用异常,因此在return语句中的布尔表达式valueProviderResult==null不能为真。” - Diego
2
注意:Phil Haack也推荐这个链接,http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx - Nathan Koop
2
我一直在使用您的原始解决方案来解决这个问题 - 谢谢!但有一个问题:null值被分配为零而不是decimal字段。最终,我选择检查valueProviderResult.RawValue == null来确定是否分配类型的默认值。 - Matt
1
这种方法对我来说很有效,但代码似乎有点不一致。首先应该检查valueProviderResult是否为null,以避免NullReferenceException,否则基础绑定将永远不会发生。然后,应该首先检查string.IsNullOrEmpty(valueProviderResult.AttemptedValue),因为在当前实现中它也会导致NullReferenceException。此外,最好检查-Infinity值。 - Eadel

13

尝试按照以下方式发送:

{ "BaseLoanAmount": "5000" }

2
我使用JSON.stringify来准备JSON,有没有服务器端的解决方案?我不想去处理客户端代码,因为它是ASP.NET MVC没有做好工作。 - ryudice
2
@ryudice,恐怕这就是JavaScript序列化器处理数字格式的方式。当你开始使用可空的十进制数、浮点数等时,情况可能会变得更加混乱。你会发现很多不一致之处。无论如何,根据JSON规范,应该始终使用引号,所以我不太确定谁没有做好他的工作。因此,在客户端对数值进行字符串化之前,您可能需要将其转换为字符串。 - Darin Dimitrov
我刚刚发现,如果我将属性类型更改为double,则绑定正常。你知道问题可能在值提供程序或模型绑定器中吗?你知道是否有一个值提供程序使用JSON.net而不是框架的JavaScript反序列化器吗? - ryudice
@ryudice,问题在于值提供程序。我不知道有哪些提供程序使用JSON.NET,但编写一个似乎很容易。你只需要确保删除旧的提供程序,否则事情可能会更加混乱 :-) - Darin Dimitrov
是的,如果十进制数以字符串格式传输,则在服务器上解析时会被正确处理,至少在我的测试中是这样。 - Stephen Patten
我使用JSON.stringify但它不起作用。 请查看 - https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify - ni3.net

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接