Asp.net mvc MVC3 RTM在反序列化JSON时无法执行数字类型强制

Asp.net mvc MVC3 RTM在反序列化JSON时无法执行数字类型强制,asp.net-mvc,model-view-controller,c#-4.0,asp.net-mvc-3,Asp.net Mvc,Model View Controller,C# 4.0,Asp.net Mvc 3,简单地说,将数据序列化为“application/json;charset=utf-8”格式在MVC3(可能还有更早的版本)中会出现错误。发生的情况是,一个可为null的数字都以null结尾,“decimal”类型的数字在javascript对象(到JSON)中序列化并保留为数字而不是字符串时以0结尾 下面是说明这种错误行为的示例代码 --此示例是使用jquery-1.4.4.js和jquery.json-2.2.js创建的----- HomeController.cs: Index.cshtm

简单地说,将数据序列化为“application/json;charset=utf-8”格式在MVC3(可能还有更早的版本)中会出现错误。发生的情况是,一个可为null的数字都以null结尾,“decimal”类型的数字在javascript对象(到JSON)中序列化并保留为数字而不是字符串时以0结尾

下面是说明这种错误行为的示例代码
--此示例是使用jquery-1.4.4.js和jquery.json-2.2.js创建的-----

HomeController.cs:

Index.cshtml:

@{
ViewBag.Title=“Index”;
}
指数
@ViewBag.SaveUrl



整数 滴答 十进制数(xx.0) 滴答 十进制数(xx.5) 滴答 整数作为字符串 滴答 十进制数字作为字符串(xx.5) 滴答 $(函数(){ var saveUrl='@ViewBag.saveUrl'; var printObj=函数(inObj,destx){ var dest=$('').appendTo(destx), dst1=$('')。附件(目的地), dst2=$('')。附件(目的地); 用于(inObj中的var p){ $('',{text:p,css:{color:'red',padding:'3px',background:'dededede'}); $('',{text:inObj[p]| | null'}).appendTo(dst2); } }; $('button.a')。单击(函数(){ var curr=$(this).next(), 输出={ 双人:12, DoubleNull:13, 小数点:14, 小数点空:15, 二比十六,, Double2Null:17, 小数点2:18, 小数点2整数:19, 单曲:20,, SingleNull:21, 浮动:22, 零时23分, 国际:24, IntNull:25, Int64:26, Int64Null:27 }; $(“
”)。附加到(当前); printObj(输出,当前); $.ajax({ 键入:“POST”, url:saveUrl, contentType:“应用程序/json;字符集=utf-8”, 数据类型:“json”, 数据:$.toJSON({ 检查表单:“fbde6eda-dde6-4ba9-b82d-3a35349415f0”, 结果:outR }), 错误:函数(jqXHR、textStatus、errorshown){ 警报(“保存失败”); }, 成功:函数(数据、文本状态、jqXHR){ printObj(数据,货币); } }); }); $('button.b')。单击(函数(){ var curr=$(this).next(), 输出={ 双倍:12.0, DoubleNull:13.0, 十进制:14.0, 小数点空:15.0, 双打2:16.0, Double2Null:17.0, 小数点2:18.0, 小数点2整数:19.0, 单曲:20.0, SingleNull:21.0, 浮动:22.0, FloatNull:23.0, 国际:24.0, IntNull:25.0, Int64:26.0, Int64Null:27.0 }; $(“
”)。附加到(当前); printObj(输出,当前); $.ajax({ 键入:“POST”, url:saveUrl, contentType:“应用程序/json;字符集=utf-8”, 数据类型:“json”, 数据:$.toJSON({ 检查表单:“fbde6eda-dde6-4ba9-b82d-3a35349415f0”, 结果:outR }), 错误:函数(jqXHR、textStatus、errorshown){ 警报(“保存失败”); }, 成功:函数(数据、文本状态、jqXHR){ printObj(数据,货币); } }); }); $('button.c')。单击(函数(){ var curr=$(this).next(), 输出={ 双倍:12.5, DoubleNull:13.5, 小数点:14.5, 小数点零:15.5, 双2:16.5,, Double2Null:17.5, 小数点2:18.5, 小数点2整数:19.5, 单曲:20.5, SingleNull:21.5, 浮动:22.5, 浮动空值:23.5, 国际:24.5, IntNull:25.5, Int64:26.5, Int64Null:27.5 }; $(“
”)。附加到(当前); printObj(输出,当前); $.ajax({ 键入:“POST”, url:saveUrl, contentType:“应用程序/json;字符集=utf-8”, 数据类型:“json”, 数据:$.toJSON({ “检查表单”:“fbde6eda-dde6-4ba9-b82d-3a35349415f0”, “结果”:outR }), 错误:函数(jqXHR、textStatus、errorshown){ 警报(“保存失败”); }, 成功:函数(数据、文本状态、jqXHR){ printObj(数据,货币); } }); }); $('button.d')。单击(函数(){ var curr=$(this).next(), 输出={ 双:“12”, DoubleNull:'13', 十进制:“14”, 小数为空:“15”, 双二:'十六',, Double2Null:'17', 小数点2:'18', 小数点2整数:“19”, 单曲:'20', 硅
public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.SaveUrl = Url.Action("Save", "Home", new { inspectionFormID = Guid.Empty }, Request.Url.Scheme);
        return View();
    }

    public JsonResult Save(Guid inspectionFormID, JsonTest result)
    {
        return Json(result);
    }

    public class JsonTest 
    {
        public double Double { get; set; }
        public double? DoubleNull { get; set; }

        public decimal Decimal { get; set; }
        public decimal? DecimalNull { get; set; }

        public Double Double2 { get; set; }
        public Double? Double2Null { get; set; }

        public Decimal Decimal2 { get; set; }
        public Decimal? Decimal2Null { get; set; }

        public Single Single { get; set; }
        public Single? SingleNull { get; set; }

        public float Float { get; set; }
        public float? FloatNull { get; set; }

        public int Int { get; set; }
        public int? IntNull { get; set; }

        public Int64 Int64 { get; set; }
        public Int64? Int64Null { get; set; }
    }

}
    @{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<b>@ViewBag.SaveUrl</b>
<br />
<hr />
<br />

<h3>Integral Numbers</h3>
<button type="button" class="a">Clicky</button>
<div></div>

<h3>Decimal Numbers (xx.0)</h3>
<button type="button" class="b">Clicky</button>
<div></div>

<h3>Decimal Numbers (xx.5)</h3>
<button type="button" class="c">Clicky</button>
<div></div>

<h3>Integral Numbers as strings</h3>
<button type="button" class="d">Clicky</button>
<div></div>

<h3>Decimal Numbers as strings (xx.5)</h3>
<button type="button" class="e">Clicky</button>
<div></div>

<script type="text/javascript">

    $(function () {
        var saveUrl = '@ViewBag.SaveUrl';

        var printObj = function (inObj, destx) {
            var dest = $('<table>').appendTo(destx),
                dst1 = $('<tr>').appendTo(dest),
                dst2 = $('<tr>').appendTo(dest);
            for (var p in inObj) {
                $('<th>', { text: p, css: { color: 'red', padding: '3px', background: '#dedede' } }).appendTo(dst1);
                $('<td>', { text: inObj[p] || 'null' }).appendTo(dst2);
            }
        };

        $('button.a').click(function () {
            var curr = $(this).next(),
                outR = {
                    Double: 12,
                    DoubleNull: 13,
                    Decimal: 14,
                    DecimalNull: 15,
                    Double2: 16,
                    Double2Null: 17,
                    Decimal2: 18,
                    Decimal2Null: 19,
                    Single: 20,
                    SingleNull: 21,
                    Float: 22,
                    FloatNull: 23,
                    Int: 24,
                    IntNull: 25,
                    Int64: 26,
                    Int64Null: 27
                };

            $('<hr />').appendTo(curr);
            printObj(outR, curr);

            $.ajax({
                type: 'POST',
                url: saveUrl,
                contentType: "application/json; charset=utf-8",
                dataType: 'json',

                data: $.toJSON({
                    inspectionFormID: 'fbde6eda-dde6-4ba9-b82d-3a35349415f0',

                    result: outR
                }),

                error: function (jqXHR, textStatus, errorThrown) {
                    alert('save failed');
                },

                success: function (data, textStatus, jqXHR) {
                    printObj(data, curr);
                }
            });
        });

        $('button.b').click(function () {
            var curr = $(this).next(),
                outR = {
                    Double: 12.0,
                    DoubleNull: 13.0,
                    Decimal: 14.0,
                    DecimalNull: 15.0,
                    Double2: 16.0,
                    Double2Null: 17.0,
                    Decimal2: 18.0,
                    Decimal2Null: 19.0,
                    Single: 20.0,
                    SingleNull: 21.0,
                    Float: 22.0,
                    FloatNull: 23.0,
                    Int: 24.0,
                    IntNull: 25.0,
                    Int64: 26.0,
                    Int64Null: 27.0
                };

            $('<hr />').appendTo(curr);
            printObj(outR, curr);

            $.ajax({
                type: 'POST',
                url: saveUrl,
                contentType: "application/json; charset=utf-8",
                dataType: 'json',

                data: $.toJSON({
                    inspectionFormID: 'fbde6eda-dde6-4ba9-b82d-3a35349415f0',

                    result: outR
                }),

                error: function (jqXHR, textStatus, errorThrown) {
                    alert('save failed');
                },

                success: function (data, textStatus, jqXHR) {
                    printObj(data, curr);
                }
            });
        });

        $('button.c').click(function () {
            var curr = $(this).next(),
                outR = {
                    Double: 12.5,
                    DoubleNull: 13.5,
                    Decimal: 14.5,
                    DecimalNull: 15.5,
                    Double2: 16.5,
                    Double2Null: 17.5,
                    Decimal2: 18.5,
                    Decimal2Null: 19.5,
                    Single: 20.5,
                    SingleNull: 21.5,
                    Float: 22.5,
                    FloatNull: 23.5,
                    Int: 24.5,
                    IntNull: 25.5,
                    Int64: 26.5,
                    Int64Null: 27.5
                };

            $('<hr />').appendTo(curr);
            printObj(outR, curr);

            $.ajax({
                type: 'POST',
                url: saveUrl,
                contentType: "application/json; charset=utf-8",
                dataType: 'json',

                data: $.toJSON({
                    'inspectionFormID': 'fbde6eda-dde6-4ba9-b82d-3a35349415f0',

                    'result': outR
                }),

                error: function (jqXHR, textStatus, errorThrown) {
                    alert('save failed');
                },

                success: function (data, textStatus, jqXHR) {
                    printObj(data, curr);
                }
            });
        });

        $('button.d').click(function () {
            var curr = $(this).next(),
                outR = {
                    Double:         '12',
                    DoubleNull:     '13',
                    Decimal:        '14',
                    DecimalNull:    '15',
                    Double2:        '16',
                    Double2Null:    '17',
                    Decimal2:       '18',
                    Decimal2Null:   '19',
                    Single:         '20',
                    SingleNull:     '21',
                    Float:          '22',
                    FloatNull:      '23',
                    Int:            '24',
                    IntNull:        '25',
                    Int64:          '26',
                    Int64Null:      '27'
                };

            $('<hr />').appendTo(curr);
            printObj(outR, curr);

            $.ajax({
                type: 'POST',
                url: saveUrl,
                contentType: "application/json; charset=utf-8",
                dataType: 'json',
                data: $.toJSON({
                    'inspectionFormID': 'fbde6eda-dde6-4ba9-b82d-3a35349415f0',

                    'result': outR
                }),

                error: function (jqXHR, textStatus, errorThrown) {
                    alert('save failed');
                },

                success: function (data, textStatus, jqXHR) {
                    printObj(data, curr);
                }
            });
    });

    $('button.e').click(function () {
        var curr = $(this).next(),
                outR = {
                    Double:         '12.5',
                    DoubleNull:     '13.5',
                    Decimal:        '14.5',
                    DecimalNull:    '15.5',
                    Double2:        '16.5',
                    Double2Null:    '17.5',
                    Decimal2:       '18.5',
                    Decimal2Null:   '19.5',
                    Single:         '20.5',
                    SingleNull:     '21.5',
                    Float:          '22.5',
                    FloatNull:      '23.5',
                    Int:            '24.5',
                    IntNull:        '25.5',
                    Int64:          '26.5',
                    Int64Null:      '27.5'
                };

        $('<hr />').appendTo(curr);
        printObj(outR, curr);

        $.ajax({
            type: 'POST',
            url: saveUrl,
            contentType: "application/json; charset=utf-8",
            dataType: 'json',
            data: $.toJSON({
                'inspectionFormID': 'fbde6eda-dde6-4ba9-b82d-3a35349415f0',

                'result': outR
            }),

            error: function (jqXHR, textStatus, errorThrown) {
                alert('save failed');
            },

            success: function (data, textStatus, jqXHR) {
                printObj(data, curr);
            }
        });
});
    });

</script>
$.ajax({
            type: 'POST',
            url: saveUrl,
            contentType: "application/json; charset=utf-8",
            dataType: 'json',

            data: $.toJSON({
                inspectionFormID: 'fbde6eda-dde6-4ba9-b82d-3a35349415f0',

                result: outR
            }),

            error: function (jqXHR, textStatus, errorThrown) {
                alert('save failed');
            },

            success: function (data, textStatus, jqXHR) {
                printObj(data, curr);
            }
        });
public class JsonTestModelBinder : IModelBinder {
    public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
        JsonTest result = new JsonTest();

        foreach (var property in typeof(JsonTest).GetProperties()) {
            //the value provider starts with the name of the property we're binding to
            //i'm not sure if this changed or not as i don't recall having to do this
            //before - you can remove "result." if your needs don't require it
            var value = bindingContext.ValueProvider.GetValue("result." + property.Name);
            if (value != null && value.RawValue != null) {
                //are we binding to a nullable?
                if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
                    property.SetValue(result, Convert.ChangeType(value.AttemptedValue, new NullableConverter(property.PropertyType).UnderlyingType), null);
                } else {
                    property.SetValue(result, Convert.ChangeType(value.AttemptedValue, property.PropertyType), null);
                }
            }
        }

        return result;
    }
}