2012-07-25 24 views
7

Estamos teniendo un problema con el encuadernador de modelo predeterminado de Nancy. Teniendo en cuenta el siguiente ...Encuadernación con modelo de Nancy a la clase infantil

public class Foo 
{ 
    public Foo() 
    { 
    } 

    public string Name { get; set; } 

    public Bar Bar { get; set; } 
} 

public class Bar 
{ 
    public string Name { get; set; } 
} 

con elementos como ...

<input type="text" value="Name" /> 
<input type="text" value="Bar.Name" /> 

con el aglutinante utilizado como modelo por defecto de manera ..

var foo = this.Bind<Foo>();

Esto se une correctamente Foo. Nombre pero no se puede unir a Foo.Bar.Name

¿Hay alguna forma de ena ¿Este tipo de enlace con el cuaderno predeterminado o tenemos que hacer el nuestro? Si es así, ¿hay algún buen ejemplo?

+0

Probablemente tengas más suerte cuando llenes un modelo de objetos javascript en el cliente y luego lo envíes en json o xml. Sé con certeza que los objetos infantiles se unirán entonces. – albertjan

Respuesta

11

Por qué no probar esto. Estoy bastante seguro de que la recursión podría optimizarse, y que algo surgirá donde no funcione, y que podría colocarse en algún lugar más inteligente que un IModelBinder, pero básicamente hace lo que quieres.

/// <summary> 
/// Sample model binder that manually binds customer models 
/// </summary> 
public class CustomModelBinder : IModelBinder 
{ 
    /// <summary> 
    /// Bind to the given model type 
    /// </summary> 
    /// <param name="context">Current context</param> 
    /// <param name="modelType">Model type to bind to</param> 
    /// <param name="blackList">Blacklisted property names</param> 
    /// <returns>Bound model</returns> 
    public object Bind(NancyContext context, Type modelType, params string[] blackList) 
    { 
     var parentObject = Activator.CreateInstance(modelType); 

     foreach (var key in context.Request.Form) 
     { 
      var value = context.Request.Form[key]; 
      this.SetObjectValue(parentObject, modelType, key, value); 
     } 

     return parentObject; 
    } 

    /// <summary> 
    /// Sets the object value. 
    /// </summary> 
    /// <param name="instance">The instance.</param> 
    /// <param name="type">The type.</param> 
    /// <param name="key">Name of the property.</param> 
    /// <param name="propertyValue">The property value.</param> 
    private void SetObjectValue(object instance, Type type, string key, string propertyValue) 
    { 
     if (key.Contains(".")) 
     { 
      this.SetObjectValueDeep(instance, type, key, propertyValue); 
     } 

     PropertyInfo propertyInfo = type.GetProperty(key); 
     if (propertyInfo == null) 
     { 
      return; 
     } 

     propertyInfo.SetValue(instance, Convert.ChangeType(propertyValue, propertyInfo.PropertyType), null); 
    } 

    /// <summary> 
    /// Sets the object value derp. 
    /// </summary> 
    /// <param name="instance">The instance.</param> 
    /// <param name="type">The type.</param> 
    /// <param name="key">The key.</param> 
    /// <param name="propertyValue">The property value.</param> 
    private void SetObjectValueDeep(object instance, Type type, string key, string propertyValue) 
    { 
     var propList = key.Split('.').ToList(); 

     PropertyInfo propertyInfo = type.GetProperty(propList.First()); 
     if (propertyInfo == null) 
     { 
      return; 
     } 

     var childObject = propertyInfo.GetValue(instance, null); 

     if (childObject == null) 
     { 
      childObject = Activator.CreateInstance(propertyInfo.PropertyType); 
      propertyInfo.SetValue(instance, childObject, null); 
     } 

     propList.RemoveAt(0); 

     var newKey = propList.Aggregate(string.Empty, (current, prop) => current + (prop + ".")).TrimEnd('.'); 

     if (newKey.Contains(".")) 
     { 
      this.SetObjectValueDeep(childObject, childObject.GetType(), newKey, propertyValue); 
     } 
     else 
     { 
      this.SetObjectValue(childObject, childObject.GetType(), newKey, propertyValue); 
     } 
    } 

    /// <summary> 
    /// Determines whether this instance can bind the specified model type. 
    /// </summary> 
    /// <param name="modelType">Type of the model.</param> 
    /// <returns> 
    /// <c>true</c> if this instance can bind the specified model type; otherwise, <c>false</c>. 
    /// </returns> 
    public bool CanBind(Type modelType) 
    { 
     return true; 
    } 
} 
+0

esto es genial, gracias. Puede ser una idea agregar el manejo de listas y publicar en GitHub. –

Cuestiones relacionadas