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

Popular posts from this blog

apache - Add omitted ? to URLs -

redirect - bbPress Forum - rewrite to wwww.mysite prohibits login -

php - How can I stop spam on my custom forum/blog? -