7

MVC3 sale de la caja con JsonValueProviderFactory() que es muy útil para vincular el JSON entrante a un modelo. Desafortunadamente, no puedo entender cómo configurar contratos modelo con nombres que difieren del JSON entrante. Por ejemplo:Enlace de modelo de DataContract a JSON en ASP.NET MVC Argumentos del método de acción

[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; } 
} 

al pasar en un objeto JSON que representa la sesión de Facebook, las propiedades secretas y expira unir correctamente, pero el resto no lo hacen debido a que el nombre de la propiedad es diferente que el nombre de la clave JSON. Esperaría que el serializador de contrato de datos intente y se vincule con el nombre provisto en el atributo, pero ese no parece ser el caso. ¿Alguien tiene alguna sugerencia de solución?

Editar

Un ejemplo de cómo iba a utilizar este modelo:

public ActionResult Log(int? custId, FacebookSession response) 
    {  
      ViewBag.Id = response.UserId;       
      return View(); 
    } 

Respuesta

6

Terminé usando el enlace de gt124 model binder example junto con a better model binder a escribir mi propia lógica enlace de modelos. Se terminó con este aspecto:

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; 
    } 
} 

Luego utiliza JSON.net atribuye a asignar a las diferentes propiedades de los objetos (en lugar de DataContracts) en los modelos. Todos los modelos se heredaron de una clase base vacía JsonModel.

+2

Asegúrese de reemplazar el encuadernador predeterminado: en Application_Start: 'ModelBinders.Binders.DefaultBinder = new SmartModelBinder (new [] {new NewtonsoftJsonModelBinder()}); ' – TodK

1

se puede pasar en forma de cadena y llamar manualmente el datacontractdeserializer, a menos que usted escribe su propia modelbinder. Creo que el encuadernador predeterminado usa el javascriptserializer, no el datacontractjsserializer.

Model Binder Example

+0

esto no funciona, la respuesta es = anular. Quiero decir, probablemente podría hacer JSON.Stringify() en la llamada js, pero eso me entristecería. –

+0

El ejemplo anterior podría darle suficiente para escribir un encuadernador que usa el datacontractjsonserializer ... – gt124

0

No es necesario reemplazar el enlazador predeterminado, acaba de escribir un atributo como la

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

el uso es sencillo

[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; } 
} 

ACTUALIZACIÓN ahora y simplemente puede utilizar una función de Json.NET funcionalidad como esa:

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

y si es necesario

var facebokSession = JsonConvert.DeserializeObject<FacebookSession>(facebookSessionJsonString); 
+1

parece prometedor. pero ¿dónde encuentro 'DataContractJsonModelBinder' ??? –

+0

@Simon_Weaver, respuesta actualizada – mumu2

Cuestiones relacionadas