Json To Dictionary generic model binder
Hey all,
Few days ago I was challenged by a good friend and colleague to write a generic model binder for a dynamic json.
Why does he need such a thing ? I'll explain:
Normally, when you write a classic website using any platform, the contract between the client and the server is obvious and well known.
However, if you write a complex web system, and you have the need to build your client model dynamically without creating a massive model on the server that handles all kinds of properties and values, you might be interested in getting a generic dictionary that contains all your client values.
To implement it I used a state machine to parse the json:
We need to register this model binder in the Global.asax file:
And the usage in the client side is pretty much straight forward as you probably expected:
That's it!
Hope you'll find it useful.
Few days ago I was challenged by a good friend and colleague to write a generic model binder for a dynamic json.
Why does he need such a thing ? I'll explain:
Normally, when you write a classic website using any platform, the contract between the client and the server is obvious and well known.
However, if you write a complex web system, and you have the need to build your client model dynamically without creating a massive model on the server that handles all kinds of properties and values, you might be interested in getting a generic dictionary that contains all your client values.
To implement it I used a state machine to parse the json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
public class DictionaryModelBinder : DefaultModelBinder { private const string _dateTimeFormat = "dd/MM/yyyy HH:mm:ss" ; private enum StateMachine { NewSection, Key, Delimiter, Value, ValueArray } public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var stream = controllerContext.HttpContext.Request.InputStream; string text; stream.Position = 0; using ( var reader = new StreamReader(stream)) { text = reader.ReadToEnd(); } int index = 0; return Build(text, ref index); } private static Dictionary< string , object > Build( string text, ref int index) { var state = StateMachine.NewSection; var dictionary = new Dictionary< string , object >(); var key = string .Empty; object value = string .Empty; for (; index < text.Length; ++index) { if (state == StateMachine.NewSection && text[index] == '{' ) { dictionary = new Dictionary< string , object >(); state = StateMachine.NewSection; } else if (state == StateMachine.NewSection && text[index] == '"' ) { key = string .Empty; state = StateMachine.Key; } else if (state == StateMachine.Key && text[index] != '"' ) { key += text[index]; } else if (state == StateMachine.Key && text[index] == '"' ) { state = StateMachine.Delimiter; } else if (state == StateMachine.Delimiter && text[index] == ':' ) { state = StateMachine.Value; value = string .Empty; } else if (state == StateMachine.Value && text[index] == '[' ) { state = StateMachine.ValueArray; value = value.ToString() + text[index]; } else if (state == StateMachine.ValueArray && text[index] == ']' ) { state = StateMachine.Value; value = value.ToString() + text[index]; } else if (state == StateMachine.Value && text[index] == '{' ) { value = Build(text, ref index); } else if (state == StateMachine.Value && text[index] == ',' ) { dictionary.Add(key, ConvertValue(value)); state = StateMachine.NewSection; } else if (state == StateMachine.Value && text[index] == '}' ) { dictionary.Add(key, ConvertValue(value)); return dictionary; } else if (state == StateMachine.Value || state == StateMachine.ValueArray) { value = value.ToString() + text[index]; } } return dictionary; } private static object ConvertValue( object value) { string valueStr; if (value is Dictionary< string , object > || value == null || (valueStr = value.ToString()).Length == 0) { return value; } bool boolValue; if ( bool .TryParse(valueStr, out boolValue)) { return boolValue; } int intValue; if ( int .TryParse(valueStr, out intValue)) { return intValue; } double doubleValue; if ( double .TryParse(valueStr, out doubleValue)) { return doubleValue; } valueStr = valueStr.Trim( '"' ); DateTime datetimeValue; if (DateTime.TryParseExact(valueStr, _dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out datetimeValue)) { return datetimeValue; } if (valueStr.First() == '[' && valueStr.Last() == ']' ) { valueStr = valueStr.Trim( '[' , ']' ); if (valueStr.Length > 0) { if (valueStr[0] == '"' ) { return valueStr .Split( new [] { '"' }, StringSplitOptions.RemoveEmptyEntries) .Where(x => x != "," ) .ToArray(); } else { return valueStr .Split( ',' ) .Select(x => ConvertValue(x.Trim())) .ToArray(); } } } return valueStr; } } |
1 |
ModelBinders.Binders.Add( typeof (Dictionary< string , object >), new DictionaryModelBinder()); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var url = '/' ; var data = { name: 'Amir Yonatan' , age: 26, height: 1.7, hasDrivingLicence: true , nicknames: [ 'amiry' , 'speedy' ], education: { graduationDate: '30/10/2010 15:12:30' , grades: [100, 95, 87], major: 'Computer Science' } }; $.ajax(url, { cache: false , contentType: 'application/json' , data: JSON.stringify(data), dataType: 'json' , type: 'POST' }); |
Hope you'll find it useful.
Comments
Post a Comment