下划线字符串模型绑定器

时间:2013-01-14 13:42:45

标签: asp.net-mvc-4 model-binding

我的印象是,当绑定到复杂模型时,会处理所有公共属性并尝试对每个属性进行匹配绑定。

我正在尝试解决变量命名问题,以便模型

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());

1 个答案:

答案 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;
    }
}