我正在使用自定义模型绑定器来绑定我的复杂类型。
以下是模型:
[ModelBinder(typeof(SupplierModelBinder))]
public class SupplierModel
{
public string VendorId { get; set; }
public string VendorName { get; set; }
public override string ToString()
{
return VendorId;
}
}
这是活页夹:
public class SupplierModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
string key = bindingContext.ModelName;
ValueProviderResult val = bindingContext.ValueProvider.GetValue(key);
if (val != null)
{
string s = val.AttemptedValue as string;
if (s != null)
{
return new SupplierModel() { VendorId = s };
}
}
return null;
}
}
我使用Html.ActionLink
使用UserModel
的{{1}}方法渲染模型。当ToString
到服务器时,它使用结果来绑定模型。
这很好用(我对这里的GET
属性并不感到烦恼),但它依赖于覆盖模型类中的VendorName
,因此我可以在模型绑定器中使用该值。 / p>
如何将复杂类型的绑定/解除绑定与ToString
方法分开?
我不想重写ToString
只是为了让我的模型正确呈现以供我的活页夹解释。对于其他类型,我必须(de)序列化为JSON或simiar,我不想在ToString
。
答案 0 :(得分:0)
我设法在不使用自定义绑定的情况下弄清楚如何执行此操作。诀窍是要意识到如果我将Supplier.VendorId="XXXX"
之类的东西作为动作链接的查询字符串的一部分进行渲染,那么它就会被正确映射。
我使用反射来查看HtmlHelper.ActionLink()
在传递对象时所执行的操作,即创建RouteValueDictionary<string, object>
的实例,该实例为对象的每个属性创建一个键。
这个默认实现接近我想要的,但我需要它来处理属性的属性。
幸运的是,ActionLink()
超载会直接占用RouteValueDictionary<string, object>
,因此我遇到了使用Property.SubProperty
类型键正确构建一个的问题。
我最终得到了以下代码,该代码首先使用RouteValueDictonary
的构造函数来获取每个属性的密钥。
然后它根据Bind
属性(如果类有一个属性)删除任何不会被绑定的东西,它会对结果查询字符串进行整理。
它的主要部分是查找...Model
类型的任何属性(类型名称以&#34结尾; Model&#34;)并将该对象的属性添加到字典中。我需要使用一些规则来判断是否递归,否则它会尝试去处理对象列表等事物的属性。我认为我已经使用了我的模型类的约定,所以我可以坚持它
public static RouteValueDictionary ToRouteValueDictionary(this object obj)
{
var Result = new RouteValueDictionary(obj);
// Find any ignored properties
var BindAttribute = (BindAttribute)obj.GetType().GetCustomAttributes(typeof(BindAttribute), true).SingleOrDefault();
var ExcludedProperties = new List<string>();
if (BindAttribute != null)
{
ExcludedProperties.AddRange(BindAttribute.Exclude.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
}
// Remove any ignored properties from the dictionary
foreach (var ExcludedProperty in ExcludedProperties)
{
Result.Remove(ExcludedProperty);
}
// Loop through each property, recursively adding sub-properties that end with "Model" to the dictionary
foreach (var Property in obj.GetType().GetProperties())
{
if (ExcludedProperties.Contains(Property.Name))
{
continue;
}
if (Property.PropertyType.Name.EndsWith("Model"))
{
Result.Remove(Property.Name);
var PropertyValue = Property.GetValue(obj, null);
if (PropertyValue != null)
{
var PropertyDictionary = PropertyValue.ToRouteValueDictionary();
foreach (var Key in PropertyDictionary.Keys)
{
Result.Add(string.Format("{0}.{1}", Property.Name, Key), PropertyDictionary[Key]);
}
}
}
}
return Result;
}