2012-01-18 9 views
12

Tengo curiosidad por saber si es posible anular el atributo [Obligatorio] que se ha establecido en un modelo. Estoy seguro de que hay una solución más simple para este problema, ¿algún tomador?¿Es posible anular el atributo requerido en una propiedad en un modelo?

+2

Definir "anular". ¿Quiere decir crear una subclase de su modelo donde esa propiedad no es necesaria, o quiere decir hacer una acción de controlador específica sin importar si no se proporciona un campo obligatorio? ¿Le preocupa la validación del lado del cliente o solo del lado del servidor? – StriplingWarrior

Respuesta

16

Depende de lo que esté haciendo exactamente. Si está trabajando con una subclase, utilizando el modelo con el atributo Requerido como base, puede hacer esto:

Redefina la propiedad con la palabra clave new, en lugar de anularla.

public class BaseModel 
{ 
    [Required] 
    public string RequiredProperty { get; set; } 
} 


public class DerivativeModel : BaseModel 
{ 
    new public string RequiredProperty { get; set; } 

} 

Si simplemente desea enlazar o validar un modelo, pero evita la propiedad requerida en su controlador, puede hacer algo como:

public ActionResult SomeAction() 
{ 
    var model = new BaseModel(); 

    if (TryUpdateModel(model, null, null, new[] { "RequiredProperty" })) // fourth parameter is an array of properties (by name) that are excluded 
    { 
      // updated and validated correctly! 
      return View(model); 
    } 
    // failed validation 
    return View(model); 
} 
+0

Perfecto, gracias! –

+0

Es posible que desee establecer y obtener de 'base', si otros dependen del campo de la clase padre:' get {return base.RequiredProperty; } set {value = base.RequiredProperty;} ' – pauloya

+2

Impar, pero eso no funcionó para mí. que tienen un atributo [Rango (0,999999)] y la clase hijo tiene [Rango (0,2000)], pero la validación recoge el padre del niño en lugar de – Nick

4

Se puede utilizar un atributo de validación personalizada (puede derivarse de RequiredAttribute):

public class RequiredExAttribute : RequiredAttribute 
    { 
     public bool UseRequiredAttribute { get; protected set; } 
     public RequiredExAttribute(bool IsRequired) 
     { 
      UseRequiredAttribute = IsRequired; 
     } 
     public override bool IsValid(object value) 
     { 
      if (UseRequiredAttribute) 
       return base.IsValid(value); 
      else 
      { 
       return true; 
      } 
     } 

     public override bool RequiresValidationContext 
     { 
      get 
      { 
       return UseRequiredAttribute; 
      } 
     } 
    } 

    public class RequiredExAttributeAdapter : RequiredAttributeAdapter 
    { 
     public RequiredExAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredExAttribute attribute) 
      : base(metadata, context, attribute) { } 

     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
     { 
      if (((RequiredExAttribute)Attribute).UseRequiredAttribute)// required -> return normal required rules 
       return base.GetClientValidationRules(); 
      else// not required -> return empty rules list 
       return new List<ModelClientValidationRule>(); 
     } 
    } 

y luego Regester en Application_Start usando esta línea código:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredExAttribute), typeof(RequiredExAttributeAdapter)); 
9

método @HackedByChinese está muy bien, pero contiene un problema

public class BaseModel 
{ 
    [Required] 
    public string RequiredProperty { get; set; } 
} 

public class DerivativeModel : BaseModel 
{ 
    new public string RequiredProperty { get; set; } 
} 

Este código le dará un error de validación en ModelState incluso si se utiliza DerivativeModel en el formulario, override tampoco funciona, por lo que no se puede eliminar Required atributo anulando o renewin, así que llegué a una cierta clase de una solución

public class BaseModel 
{ 
    public virtual string RequiredProperty { get; set; } 
} 

public class DerivativeModel : BaseModel 
{ 
    [Required] 
    public override string RequiredProperty { get; set; } 
} 

public class DerivativeModel2 : BaseModel 
{ 
    [Range(1, 10)] 
    public override string RequiredProperty { get; set; } 
} 

que tienen un modelo de base sin los atributos de validación y clase derivada es

+0

gracias que escribió sobre el error de validación de ModelState, pensé que estaba haciendo algo mal – RMazitov

1

Probé la respuesta de Mahmoud, pero no funcionó para mí sin algunos cambios. Agregando esto como una respuesta para que pueda dar el código que lo hizo en caso de que ayude a alguien más, pero con todo el mérito de Mahmoud Hboubati - He votado a favor su respuesta.

En mi situación, tenía una clase DTO base con una propiedad DbGeography que era necesaria para un proyecto MVC que utilizaba un EditorTemplate personalizado y DisplayTemplate para el tipo DbGeography. Pero para publicar un modelo en un controlador de API web, quería agregar campos de latitud/longitud a una subclase de ese DTO, que se usaría para crear y establecer una instancia de una clase DbGeography para establecer el valor en la propiedad DbGeography. El problema era que no podía hacer que la propiedad DbGeography no fuera requerida solo en la subclase.

Cuando se pasó el valor booleano en el constructor utilizando el enfoque de Mahmoud, nunca pareció anular el valor predeterminado para mí. Eso podría ser porque estoy usando API web y registrando el atributo usando el enfoque de fábrica, como a continuación (en Global.asax.cs método Application Start):

DataAnnotationsModelValidationFactory factory = (p, a) => new DataAnnotationsModelValidator(
    new List<ModelValidatorProvider>(), new RequiredExAttribute() 
); 

DataAnnotationsModelValidatorProvider provider = new DataAnnotationsModelValidatorProvider(); 
provider.RegisterAdapterFactory(typeof(RequiredExAttribute), factory); 

que tuvo que cambiar la clase de atributo a esto:

using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Web.Mvc; 
... 
public class RequiredExAttribute : RequiredAttribute 
{ 
    public bool IsRequired { get; set; } 

    public override bool IsValid(object value) 
    { 
     if (IsRequired) 
      return base.IsValid(value); 
     else 
     { 
      return true; 
     } 
    } 

    public override bool RequiresValidationContext 
    { 
     get 
     { 
      return IsRequired; 
     } 
    } 
} 

public class RequiredExAttributeAdapter : RequiredAttributeAdapter 
{ 
    public RequiredExAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredExAttribute attribute) 
     : base(metadata, context, attribute) { } 

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
    { 
     if (((RequiredExAttribute)Attribute).IsRequired)// required -> return normal required rules 
      return base.GetClientValidationRules(); 
     else// not required -> return empty rules list 
      return new List<ModelClientValidationRule>(); 
    } 
} 

clase de base:

[RequiredEx(IsRequired = true)] 
public virtual DbGeography Location { get; set; } 

Subclase:

[RequiredEx(IsRequired = false)] 
public override DbGeography Location { get; set; } 

[Required] 
public decimal Latitude { get; set; } 

[Required] 
public decimal Longitude { get; set; } 

Nota, Usé el mismo método que Mahmoud hizo arriba para registrar el atributo en mi proyecto MVC:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredExAttribute), typeof(RequiredExAttributeAdapter)); 
1

Sí, es posible utilizar el MetadataType clase, por ejemplo:

[MetadataType(typeof(Base.Metadata))] 
public class Base 
{  
    public string RequiredProperty { get; set; } 

    public class Metadata 
    { 
     [Required] 
     public string RequiredProperty { get; set; } 
    } 
} 

[MetadataType(typeof(Derived.Metadata))] 
public class Derived : Base 
{ 
    public new class Metadata 
    { 
    } 
} 

y probarlo:

var type = typeof(Derived); 

var metadataType = typeof(Derived.Metadata); 

var provider = new AssociatedMetadataTypeTypeDescriptionProvider(type, metadataType); 

TypeDescriptor.AddProviderTransparent(provider, type); 

var instance = new Derived(); 

var results = new List<ValidationResult>(); 

Validator.TryValidateObject(instance, 
    new ValidationContext(instance), 
    results, 
    true); 

Debug.Assert(results.Count == 0); 
Cuestiones relacionadas