Finding custom attributes on view model properties when model binding
asp.net-mvc, custom-attributes, model-binding
Solution
The "correct" way (per the guy who wrote it) is to write a model metadata provider. There's an example at the link. Not precisely "simple," but it works, and you'll be doing what the rest of MVC does.
Problem
I've found a lot of information on implementing a custom model binder for validation purposes but I haven't seen much about what I'm attempting to do. I want to be able to manipulate the values that the model binder is going to set based on attributes on the property in the view model. For instance: ``` public class FooViewModel : ViewModel { [AddBar] public string Name { get; set; } } ``` AddBar is just ``` public class AddBarAttribute : System.Attribute { } ``` I've not been able to find a clean way to find the attributes on a view model property in the custom model binder's BindModel method. This works but it feels like there should be a simpler solution: ``` public class FooBarModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var value = base.BindModel(controllerContext, bindingContext); var hasBarAttribute = false; if(bindingContext.ModelMetadata.ContainerType != null) { var property = bindingContext.ModelMetadata.ContainerType.GetProperties() .Where(x => x.Name == bindingContext.ModelMetadata.PropertyName).FirstOrDefault(); hasBarAttribute = property != null && property.GetCustomAttributes(true).Where(x => x.GetType() == typeof(AddBarAttribute)).Count() > 0; } if(value.GetType() == typeof(String) && hasBarAttribute) value = ((string)value) + "Bar"; return value; } } ``` Is there a cleaner way to view the attributes on the view model property or a different kind of attribute I could be using? The DataAnnotation attributes really seem to be for a different problem. UPDATE Craig's answer got me to the right place but I thought I'd put some examples in here for others. The metadata provider I ended up with looks like ``` public class FooBarModelMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { var metaData = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); if(attributes.OfType<AddBarAttribute>().Any()) metaData.AdditionalValues.Add("AddBarKey", true); return metaData; } } ``` The model binder looks like: ``` public class FooBarModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var value = base.BindModel(controllerContext, bindingContext); if(bindingContext.ModelMetadata.AdditionalValues.ContainsKey("AddBarKey")) value = ((string)value) + "Bar"; return value; } } ```