Question

Is it possible in .net mvc5 to bind an attribute according to a specific rule? So for example, I have a time input (e.g. 10.30) and I need to bind that to a double. I was hoping for something along the lines of this:

// Model
[CustomAttribute("TimeAttr")]
public double Hours { get; set; }

// Binding
public TimeAttrBinder : IModelBinder
{
    // Replace colons with dots
    return double.Parse(value.Replace(':', '.'));
}

// Global
ModelBinders.add("TimeAttr", TimeAttrBinder)

So that I can put an annotation on the attribute in the model, and that it's custom model binded everytime...

Is such a thing possible in .net mvc5?

Was it helpful?

Solution

There's no built-in mechanism for that but you could build a custom PropertyBinder attribute that will apply the model binder only for a given property as shown in this article: http://aboutcode.net/2011/03/12/mvc-property-binder.html

You could make it pretty generic as illustrated in the article but to illustrate the concept you could try something like this.

A metadata aware marker attribute:

public class MyMarkerAttribute : Attribute, IMetadataAware
{
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["marker"] = true;
    }
}

A custom model binder that will understand this marker attribute:

public class MyModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelMetadata.AdditionalValues.ContainsKey(MyMarkerAttribute.MarkerKey))
        {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (value != null)
            {
                // Here you could implement whatever custom binding logic you need
                // for your property from the binding context
                return value.ConvertTo(typeof(double));
            }
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

and then replace the default model binder with the custom one in your Application_Start:

ModelBinders.Binders.DefaultBinder = new MyModelBinder();

and that's pretty much it. Now you could decorate your view model with the marker attribute:

[MyMarker]
public double Hours { get; set; }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top