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 a variable naming problem so that a model
class Model {
public string Foo {get;set;}
public string FooBar {get;set;}
}
works nicely with a query string like
?foo=foo&foo_bar=foo_bar
Is there a better way than with a custom model binder? In any case, mine doesn't work. FooBar is simply skipped.
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;
}
}
Registered with
ModelBinders.Binders.Add(typeof(string), new StringModelBinder());
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:
So let's implement this. We start by writing a base attribute:
and a custom model binder:
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
:and all that's left now is to implement the ParameterNameAttribute binder that we used to decorate our model property with: