2011-06-01 18 views
14

He encontrado mucha información sobre la implementación de un archivador de modelo personalizado con fines de validación, pero no he visto mucho sobre lo que estoy tratando de hacer.Encontrar atributos personalizados en las propiedades del modelo de vista cuando se vincula el modelo

Quiero ser capaz de manipular los valores que el archivador modelo va a establecer en función de los atributos en la propiedad en el modelo de vista. Por ejemplo:

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

AddBar es sólo

public class AddBarAttribute : System.Attribute 
{ 
} 

no he sido capaz de encontrar una manera limpia para encontrar los atributos de una propiedad vista del modelo en el método bindModel el modelo de carpeta de encargo. Esto funciona, pero se siente que debe haber una solución más simple:

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

¿Hay una manera más limpia para ver los atributos de la propiedad vista del modelo o de otro tipo de atributo que pudiera utilizar? Los atributos de DataAnnotation realmente parecen ser para un problema diferente.

ACTUALIZACIÓN

respuesta de Craig me llegó al lugar correcto, pero pensé que había puesto algunos ejemplos aquí para otros.

El proveedor de metadatos que terminó con miradas como

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

El modelo ligante se parece a:

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

Respuesta

7

La forma "correcta" (por el tipo que lo escribió) es write a model metadata provider. Hay un ejemplo en el enlace. No es precisamente "simple", pero funciona, y harás lo que hace el resto de MVC.

+0

Pensé que tenía sentido después de seguir su enlace, pero ahora no estoy tan seguro. En realidad, no quiero cambiar los valores de ninguna de las propiedades de anotación de datos tanto como cambiar el valor del modelo en sí en función de una nueva propiedad (al agregar "Barra" al final del ejemplo anterior). Llamar a metaData.Model + = "Barra" no parece tener ningún efecto en nada. – Jared

+0

Después de haber agregado sus tokens personalizados a los metadatos del modelo, puede cambiar el encuadernador del modelo para que los reconozca. –

+2

Gracias por el puntero. Actualicé la publicación principal con algunos ejemplos basados ​​en el enlace que compartiste. – Jared

Cuestiones relacionadas