Underscore string model binder

后端 未结 1 1718
甜味超标
甜味超标 2021-01-06 07:56

I was under the impression that when binding to a complex model, all public properties were processed and a match binding attempted for each.

I\'m trying to resolve

相关标签:
1条回答
  • 2021-01-06 08:59

    I was under the impression that when binding to a complex model, all public properties were processed and a match binding attempted for each.

    No, that's a wrong impression. The default model binder will attempt to bind only the properties for which you have a corresponding value in the Request. In your case you do not have a corresponding value for the FooBar property so it won't be bound.

    Actually it would be nice if we could write:

    public class Model
    {
        public string Foo { get; set; }
    
        [ParameterName("foo_bar")]
        public string FooBar { get; set; }
    }
    

    So let's implement this. We start by writing a base attribute:

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

    and a custom model binder:

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

    As you can see this custom model analyzes the metadata of the model and if a property is decorated with an instance of the PropertyBinderAttribute it will use it.

    We will then replace the default model binder with our custom one in Application_Start:

    ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
    

    and all that's left now is to implement the ParameterNameAttribute binder that we used to decorate our model property with:

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题