我的印象是,当绑定到复杂模型时,会处理所有公共属性并尝试对每个属性进行匹配绑定。
我正在尝试解决变量命名问题,以便模型
class Model {
public string Foo {get;set;}
public string FooBar {get;set;}
}
可以很好地处理像
这样的查询字符串?foo=foo&foo_bar=foo_bar
有没有比自定义模型绑定器更好的方法?无论如何,我的工作不起作用。简单地跳过了FooBar。
public class StringModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = base.BindModel(controllerContext, bindingContext);
if (model != null)
return model;
var modelName = Regex.Replace(bindingContext.ModelName, "([a-z])([A-Z])", "$1_$2").ToLowerInvariant();
var value = bindingContext.ValueProvider.GetValue(modelName);
return value;
}
}
注册
ModelBinders.Binders.Add(typeof(string), new StringModelBinder());
答案 0 :(得分:15)
我的印象是,当绑定到复杂模型时,所有 处理公共属性并尝试匹配绑定 每个
不,这是一个错误的印象。默认模型绑定器将尝试仅绑定在Request中具有相应值的属性。在您的情况下,您没有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;
}
}