是否可以覆盖模型中特性的必需属性
本文关键字:属性 覆盖 模型 是否 | 更新日期: 2023-09-27 18:20:49
我很想知道是否可以覆盖在模型上设置的[Required]属性。我相信这个问题有一个简单的解决方案,有人愿意接受吗?
具体取决于您在做什么。如果您正在使用一个子类,使用具有Required属性的模型作为基础,您可以这样做:
使用new
关键字重新定义属性,而不是覆盖它。
public class BaseModel
{
[Required]
public string RequiredProperty { get; set; }
}
public class DerivativeModel : BaseModel
{
new public string RequiredProperty { get; set; }
}
如果您只是想绑定或验证模型,但跳过控制器中的Required属性,则可以执行以下操作:
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);
}
@HackedByChinese方法很好,但它包含一个问题
public class BaseModel
{
[Required]
public string RequiredProperty { get; set; }
}
public class DerivativeModel : BaseModel
{
new public string RequiredProperty { get; set; }
}
这段代码在ModelState
中给你一个验证错误,即使你在表单上使用DerivativeModel
,override
也不起作用,所以你不能通过重写或续订Required
属性来删除它,所以我找到了一种解决方法
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; }
}
我有一个没有验证属性的基本模型和派生类
您可以使用自定义验证属性(它可能源自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>();
}
}
然后使用以下代码行在Application_Start
中正则化它:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredExAttribute), typeof(RequiredExAttributeAdapter));
是的,可以使用MetadataType类,例如:
[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);
我尝试了Mahmoud的答案,但如果不做一些更改,它对我来说就不起作用。添加这个作为答案,这样我就可以给出这样做的代码,以防它帮助其他人,但这完全归功于Mahmoud Hboubati——我已经投票支持你的答案。
在我的情况下,我有一个带有DbGeography属性的基本DTO类,这是MVC项目所必需的,该项目为DbGeographic类型使用了自定义EditorTemplate和DisplayTemplate。但是,为了将模型发布到Web API控制器,我希望将纬度/经度字段添加到该DTO的子类中,该子类将用于创建和设置DbGeography类的实例,以设置DbGeology属性上的值。问题是,我无法使DbGeography属性仅在子类上是不需要的。
当使用Mahmoud的方法在构造函数中传递布尔值时,它似乎从未覆盖我的默认值。这可能是因为我使用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; }
注意,我在MVC项目中使用了和Mahmoud相同的方法来注册属性:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredExAttribute), typeof(RequiredExAttributeAdapter));