Поиск пользовательских атрибутов в свойствах модели просмотра при привязке модели

#asp.net-mvc #custom-attributes #model-binding

#asp.net-mvc #пользовательские атрибуты #привязка модели

Вопрос:

Я нашел много информации о реализации пользовательского связующего элемента модели для целей проверки, но я мало что видел о том, что я пытаюсь сделать.

Я хочу иметь возможность манипулировать значениями, которые связующее устройство модели собирается установить на основе атрибутов свойства в модели представления. Например:

 public class FooViewModel : ViewModel
{
    [AddBar]
    public string Name { get; set; }
}
  

AddBar — это просто

 public class AddBarAttribute : System.Attribute
{
}
  

Мне не удалось найти простой способ поиска атрибутов в свойстве модели просмотра в методе bindModel пользовательской модели binder. Это работает, но кажется, что должно быть более простое решение:

 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 amp;amp; property.GetCustomAttributes(true).Where(x => x.GetType() == typeof(AddBarAttribute)).Count() > 0;
        }

        if(value.GetType() == typeof(String) amp;amp; hasBarAttribute)
            value = ((string)value)   "Bar";

        return value;
    }
}
  

Есть ли более чистый способ просмотра атрибутов в свойстве модели просмотра или другой вид атрибута, который я мог бы использовать? Атрибуты DataAnnotation, похоже, действительно предназначены для другой проблемы.

Обновить

Ответ Крейга привел меня в нужное место, но я подумал, что приведу здесь несколько примеров для других.

Поставщик метаданных, с которым я закончил, выглядит как

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

Привязка модели выглядит следующим образом:

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

Ответ №1:

«Правильный» способ (согласно парню, который его написал) — написать поставщика метаданных модели. По ссылке есть пример. Не совсем «просто», но это работает, и вы будете делать то, что делает остальная часть MVC.

Комментарии:

1. Я думал, что это имеет смысл после перехода по вашей ссылке, но теперь я не так уверен. На самом деле я не столько хочу изменять значения каких-либо свойств аннотации данных, сколько изменять значение самой модели на основе нового свойства (путем добавления «Bar» в конец из моего примера выше). Вызов метаданных. Модель = «Bar», похоже, на самом деле ни на что не влияет.

2. Добавив свои пользовательские токены в метаданные модели, вы можете затем изменить привязку модели, чтобы распознавать их.

3. Спасибо за указатель. Я обновил основной пост некоторыми примерами, основанными на ссылке, которой вы поделились.