简体   繁体   English

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

[英]Is it possible to override the required attribute on a property in a model?

I'm curious to find out if it is possible to override the [Required] attribute that has been set on a model. 我很想知道是否可以覆盖模型上设置的[Required]属性。 I'm sure there most be a simple solution to this problem, any takers? 我相信这个问题最简单的解决方案,任何接受者?

Depends on what precisely you are doing. 取决于你究竟在做什么。 If you are working with a subclass, using the model with the Required attribute as the base, you can do this: 如果您正在使用子类,使用具有Required属性作为基础的模型,您可以执行以下操作:

Redefine the property with the new keyword, rather than override it. 使用new关键字重新定义属性,而不是覆盖它。

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


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

}

If you simply want to bind or validate a model, but skip the Required property in your controller, you can do something like: 如果您只想绑定或验证模型,但跳过控制器中的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 method is fine, but it contains a problem @HackedByChinese方法很好,但它包含一个问题

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

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

This code give you a validation error in ModelState EVEN if you use DerivativeModel on the form, override doesn't work either, so you cannot delete Required attribute by overriding or renewin it, so I came to a some sort of a workaround 如果在表单上使用DerivativeModel ,此代码会在ModelState EVEN中给出验证错误, 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; }
}

I have a base model with no validation attributes and derived classes 我有一个没有验证属性和派生类的基本模型

You can use a custom validation attribute (it might be derived from RequiredAttribute): 您可以使用自定义验证属性(它可能来自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>();
        }
    }

and then regester it in Application_Start using this code line: 然后使用以下代码行在Application_Start重新设置它:

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

I tried Mahmoud's answer, but it didn't work for me without a few changes. 我尝试了Mahmoud的答案,但如果没有一些变化,它对我没有用。 Adding this as an answer so I can give the code that did in case it helps someone else, but full credit to Mahmoud Hboubati - I've upvoted your answer. 添加这个作为答案,所以我可以给出代码,以防万一它帮助其他人,但完全归功于Mahmoud Hboubati - 我已经赞成你的答案。

In my situation I had a base DTO class with a DbGeography property that was required for an MVC project which used a custom EditorTemplate and DisplayTemplate for the DbGeography type. 在我的情况下,我有一个基础DTO类,它具有一个MVC项目所需的DbGeography属性,该项目使用自定义EditorTemplate和DisplayTemplate作为DbGeography类型。 But for posting a model to a Web API controller I wanted to have latitude/longitude fields added to a subclass of that DTO instead, which would be used to create and set an instance of a DbGeography class to set the value on the DbGeography property. 但是,为了将模型发布到Web API控制器,我希望将纬度/经度字段添加到该DTO的子类中,这将用于创建和设置DbGeography类的实例以在DbGeography属性上设置值。 Problem was, I couldn't make the DbGeography property not required on the subclass only. 问题是,我不能仅在子类上不需要DbGeography属性。

When the boolean value was passed in the constructor using Mahmoud's approach, it never seemed to override the default value for me. 当使用Mahmoud的方法在构造函数中传递布尔值时,它似乎永远不会覆盖我的默认值。 That might be because I'm using Web API and registering the attribute using the factory approach, like below (in Global.asax.cs Application_Start method): 这可能是因为我正在使用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);

I had to change the attribute class to this: 我不得不将属性类更改为:

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

Base Class: 基类:

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

Subclass: 子类:

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

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

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

Note, I used same method as Mahmoud did above for registering the attribute in my MVC project: 注意,我使用与上面Mahmoud相同的方法在我的MVC项目中注册属性:

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

Yes, it is possible using the MetadataType class, eg: 是的,可以使用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
    {
    }
}

And test it: 并测试它:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM