下划线字符串模型绑定器

Mar*_*tin 4 model-binding asp.net-mvc-4

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

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

class Model {
      public string Foo {get;set;}
      public string FooBar {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

与查询字符串很好地配合使用

?foo=foo&foo_bar=foo_bar
Run Code Online (Sandbox Code Playgroud)

有没有比自定义模型绑定器更好的方法?无论如何,我的工作不起作用.简单地跳过了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;
        }

    }
Run Code Online (Sandbox Code Playgroud)

注册

ModelBinders.Binders.Add(typeof(string), new StringModelBinder());
Run Code Online (Sandbox Code Playgroud)

Dar*_*rov 15

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

不,这是一个错误的印象.默认模型绑定器将尝试仅绑定在Request中具有相应值的属性.在您的情况下,您没有FooBar属性的相应值,因此它不会被绑定.

实际上,如果我们能写出来会很好:

public class Model
{
    public string Foo { get; set; }

    [ParameterName("foo_bar")]
    public string FooBar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

所以让我们实现这一点.我们首先编写一个基本属性:

[AttributeUsageAttribute(AttributeTargets.Property)]
public abstract class PropertyBinderAttribute : Attribute, IModelBinder
{
    public abstract object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
}
Run Code Online (Sandbox Code Playgroud)

和自定义模型绑定器:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,此自定义模型分析模型的元数据,如果使用PropertyBinderAttribute的实例修饰属性,它将使用它.

然后我们将使用我们的自定义模板绑定器替换默认模型绑定器Application_Start:

ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
Run Code Online (Sandbox Code Playgroud)

现在剩下的就是实现我们用来装饰我们的模型属性的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;
    }
}
Run Code Online (Sandbox Code Playgroud)