我的印象是,当绑定到复杂模型时,所有公共属性都已处理,并尝试为每个属性进行匹配绑定。
不,这是错误的印象。默认模型绑定器将尝试仅绑定您在请求中具有相应值的属性。在您的情况下,您没有 FooBar 属性的相应值,因此它不会被绑定。
实际上,如果我们可以这样写就好了:
public class Model
{
public string Foo { get; set; }
[ParameterName("foo_bar")]
public string FooBar { get; set; }
}
所以让我们实现它。我们首先编写一个基本属性:
[AttributeUsageAttribute(AttributeTargets.Property)]
public abstract class PropertyBinderAttribute : Attribute, IModelBinder
{
public abstract object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
}
和一个自定义模型绑定器:
public class CustomModelBinder : DefaultModelBinder
{
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
{
var propertyBinderAttribute = propertyDescriptor
.Attributes
.OfType<PropertyBinderAttribute>()
.FirstOrDefault();
if (propertyBinderAttribute != null)
{
var value = propertyBinderAttribute.BindModel(controllerContext, bindingContext);
propertyDescriptor.SetValue(bindingContext.Model, value);
}
else
{
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
}
}
如您所见,此自定义模型分析模型的元数据,并且如果使用 PropertyBinderAttribute 的实例修饰属性,它将使用它。
然后,我们将用我们的自定义模型替换默认模型绑定器Application_Start
:
ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
现在剩下的就是实现我们用来装饰模型属性的 ParameterNameAttribute 绑定器:
public class ParameterNameAttribute : PropertyBinderAttribute
{
private readonly string parameterName;
public ParameterNameAttribute(string parameterName)
{
this.parameterName = parameterName;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(this.parameterName);
if (value != null)
{
return value.AttemptedValue;
}
return null;
}
}