2012-07-25 59 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