23

モデルに設定された [Required] 属性をオーバーライドできるかどうか知りたいです。この問題には簡単な解決策があると確信しています。

4

5 に答える 5

25

正確に何をしているかによって異なります。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);
}
于 2012-01-18T00:58:42.737 に答える
7

カスタム検証属性を使用できます (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));
于 2014-06-17T08:40:35.977 に答える
2

はい、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);
于 2017-03-13T15:03:35.887 に答える
1

マフムードの答えを試しましたが、いくつか変更しないとうまくいきませんでした。これを回答として追加して、他の誰かに役立つ場合に備えてコードを提供できるようにしますが、Mahmoud Hboubati に完全なクレジットを与えます-私はあなたの回答に賛成しました。

私の状況では、DbGeography タイプのカスタム EditorTemplate と DisplayTemplate を使用する MVC プロジェクトに必要な DbGeography プロパティを持つ基本 DTO クラスがありました。しかし、モデルを 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; }

MVCプロジェクトに属性を登録するためにMahmoudが上記で行ったのと同じ方法を使用したことに注意してください。

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredExAttribute), typeof(RequiredExAttributeAdapter));
于 2016-11-10T18:09:38.457 に答える