是否有可能覆盖模型中属性的必需属性?

问题描述:

我很想知道是否可以重写已经在模型上设置的[Required]属性。我敢肯定,这个问题最简单的解决方案,任何接受者?是否有可能覆盖模型中属性的必需属性?

+2

定义 “覆盖”。你的意思是在你不需要这个属性的情况下创建你的模型的子类,或者你的意思是做一个特定的控制器动作不关心是否没有提供必需的字段?你担心客户端验证还是服务器端? – StriplingWarrior 2012-01-18 01:00:19

取决于你在做什么。如果您正在使用子类,那么使用Required属性为基础的模型,可以这样做:

使用new关键字重新定义属性,而不是覆盖它。

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


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

} 

如果你只是想绑定或验证的模型,但跳过所需的财产在你的控制器,你可以这样做:

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

完美,谢谢! – 2012-01-18 01:22:23

+0

如果别人依赖父类字段,你可能想要设置和从'base'获取:'get {return base.RequiredProperty; } set {value = base.RequiredProperty;}' – pauloya 2013-08-22 14:58:28

+2

奇怪,但没有为我工作。 我有一个属性[范围(0,999999)和子类有[范围(0,2000)],但验证拿起父母,而不是孩子 – Nick 2014-03-28 14:10:17

您可以使用自定义验证属性(它可能从RequiredAttribute标签导出):

0123:

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

,然后使用此代码行里杰斯特它在

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

@HackedByChinese方法是好的,但它包含了一个问题

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

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

此代码给你一个验证错误在ModelState即使你在表单上使用DerivativeModeloverride也不管用,所以你无法通过覆盖删除Required属性或renewin,所以我来到了某种变通方法

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

我有没有验证属性和派生类示范基地es

+0

非常感谢你对ModelState验证错误的怀疑,我以为我做错了什么 – RMazitov 2016-01-14 10:46:47

我试过马哈茂德的答案,但它没有对我做任何改动。作为回答添加这个,所以我可以给它的代码,以防万一它帮助别人,但充分相信马哈茂德Hboubati - 我已upvoted你的答案。

在我的情况下,我有一个DbGeography属性的基类DTO类,这是一个MVC项目所需的,它使用自定义EditorTemplate和DisplayTemplate作为DbGeography类型。但是,为了将模型发布到Web API控制器,我希望将纬度/经度字段添加到该DTO的子类中,以用于创建和设置DbGeography类的实例,以在DbGeography属性上设置该值。问题是,我无法仅在子类上创建不需要的DbGeography属性。

当使用马哈茂德的方法在构造函数中传递布尔值时,它似乎从未覆盖默认值。这可能是因为我正在使用Web API并使用工厂方法注册属性,如下所示(在Global.asax中。CS Application_Start方法中):

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

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

我不得不改变属性类此:

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

基类:

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

子类:

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

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

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

注,我使用了与上面Mahmoud相同的方法在我的MVC项目中注册的属性:

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

是的,有可能使用MetadataType类,e.g:

[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 
    { 
    } 
} 

并对其进行测试:

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