Binding a DataContract Model to JSON in ASP.NET MVC Action Method Arguments

MVC3 goes out of the box with JsonValueProviderFactory (), which is very convenient for binding incoming JSON to the model. Unfortunately, I cannot figure out how to set up model contracts with names that are different from incoming JSON. For example:

[DataContract(Name = "session")] public class FacebookSession { [DataMember(Name = "access_token")] public string AccessToken { get; set; } [DataMember(Name = "expires")] public int? Expires { get; set; } [DataMember(Name = "secret")] public string Secret { get; set; } [DataMember(Name = "session_key")] public string Sessionkey { get; set; } [DataMember(Name = "sig")] public string Signature { get; set; } [DataMember(Name = "uid")] public string UserId { get; set; } } 

when passed in a json object representing a facebook session, the properties are secret and end accordingly, but the rest is not because the property name is different from the json key name. I would expect the datacontract serializer to try to bind the name specified in the attribute, but that doesn't seem to be the case. Does anyone have any workarounds?

Edit

An example of how I will use this model:

  public ActionResult Log(int? custId, FacebookSession response) { ViewBag.Id = response.UserId; return View(); } 
+7
source share
3 answers

In the end, I used the gt124 link as an example of a connecting device , but rather a model binder , to write my own model binding logic. It looked like this:

 public interface IFilteredModelBinder : IModelBinder { bool IsMatch(Type modelType); } public class SmartModelBinder : DefaultModelBinder { private readonly IFilteredModelBinder[] _filteredModelBinders; public SmartModelBinder(IFilteredModelBinder[] filteredModelBinders) { _filteredModelBinders = filteredModelBinders; } public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { foreach (var filteredModelBinder in _filteredModelBinders) { if (filteredModelBinder.IsMatch(bindingContext.ModelType)) { return filteredModelBinder.BindModel(controllerContext, bindingContext); } } return base.BindModel(controllerContext, bindingContext); } } public class NewtonsoftJsonModelBinder : IFilteredModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) { // not JSON request return null; } var request = controllerContext.HttpContext.Request; request.InputStream.Position = 0; var incomingData = new StreamReader(request.InputStream).ReadToEnd(); if (String.IsNullOrEmpty(incomingData)) { // no JSON data return null; } object ret = JsonConvert.DeserializeObject(incomingData, bindingContext.ModelType); return ret; } public bool IsMatch(Type modelType) { var ret = (typeof(JsonModel).IsAssignableFrom(modelType)); return ret; } } 

Then I used the JSON.net attributes to map to the various properties of the object (instead of DataContracts) on the models. Models inherited from an empty JsonModel base class.

+6
source

You can pass it as a string and manually call the datacontractdeserializer, unless you have written your own model block. I believe the binder uses the javascriptserializer by default, not the datacontractjsserializer.

Model Binding Example

+1
source

You do not need to replace the default binder, just write such an attribute

 public class DataContractJsonModelBinderAttribute : CustomModelBinderAttribute { public override IModelBinder GetBinder() { return new DataContractJsonModelBinder(); } } 

simple use

 [DataContract(Name = "session")] [DataContractJsonModelBinder] public class FacebookSession { [DataMember(Name = "access_token")] public string AccessToken { get; set; } [DataMember(Name = "expires")] public int? Expires { get; set; } [DataMember(Name = "secret")] public string Secret { get; set; } [DataMember(Name = "session_key")] public string Sessionkey { get; set; } [DataMember(Name = "sig")] public string Signature { get; set; } [DataMember(Name = "uid")] public string UserId { get; set; } } 

UPDATE Now you can simply use the built-in functions of Json.NET:

 [JsonObject] public class FacebookSession { [JsonProperty("access_token")] public string AccessToken { get; set; } } 

and if necessary

 var facebokSession = JsonConvert.DeserializeObject<FacebookSession>(facebookSessionJsonString); 
0
source

All Articles