2012-07-25 68 views
7

我们遇到了Nancy的默认模型绑定器的问题。下面给出了...Nancy模型绑定到子类

public class Foo 
{ 
    public Foo() 
    { 
    } 

    public string Name { get; set; } 

    public Bar Bar { get; set; } 
} 

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

具有相似元素...

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

随着使用像这样的默认模型绑定..

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

这正确结合美孚。名称但未绑定Foo.Bar.Name

有没有办法ena可以将这种绑定与默认绑定器绑定,还是需要自己推出?如果有,有什么好的例子吗?

+0

当你在客户端填充javascript对象模型,然后用json或xml提交时,你可能会有更好的运气。我肯定知道那些子对象会被绑定。 – albertjan 2012-07-25 12:36:09

回答

11

为什么不试试这个。我相当肯定递归可以被优化,并且有些东西会出现在它不起作用的地方,并且它可能被放在比IModelBinder更聪明的地方,但它基本上可以做你想要的。

/// <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

这很好,谢谢。可能是添加处理列表并发布到GitHub的想法。 – 2012-07-25 19:18:13