asp.net mvc - MVC3 RTM fails number type coercion when deserializing JSON -
simply put serializing data in "application/json; charset=utf-8" format misbehaves in mvc3 (and possibly older versions). happens nullable numbers end null, , numbers of "decimal" type end 0 when serializing them inside javascript object (to json) , leaving them numbers , not strings.
here example code illustrates misbehavior
- - - example created using jquery-1.4.4.js , jquery.json-2.2.js - - - -
homecontroller.cs:
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; } } }
index.cshtml:
@{ 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 strings</h3> <button type="button" class="d">clicky</button> <div></div> <h3>decimal numbers 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); (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>
run click each button once, , @ before/after. in advance insight, correction or can provide resolve issue.
you can download code samples listed above , see official bug report @ link: http://aspnet.codeplex.com/workitem/8114
edit: including image what's going on here
click here see screenshot of included example running
basically: { propertythatisadecimal: 54 } becomes { propertythatisadecimal: 0 } on server multiple different number types in varying scenarios there doesn't seem rhyme or reason to.
the reason because when mvc encounters number treats int32
. such there no converters, reason, int32
decimal
or nullable<int64>
. there couple ways around issue. strings, have in project or create custom model binder.
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 name of property we're binding //i'm not sure if changed or not don't recall having //before - can remove "result." if needs don't require var value = bindingcontext.valueprovider.getvalue("result." + property.name); if (value != null && value.rawvalue != null) { //are binding 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; } }
i'm not entirely sure why still can't convert int32
decimal
problem exists within mvc's valueproviderresult.convertsimpletype
. it's using typedescriptor.getconverter(your propertytype)
, there's no conversions available types.
i don't particular method it's 1 available now.
Comments
Post a Comment