3 回答
TA贡献1820条经验 获得超9个赞
基于最初的实现,我建议扩展RequiredAttribute而不是ValidationAttribute- 然后根据 [Required] 设置默认的 ErrorMessage 和其他默认值。无论哪种方式,“errormessage”属性都是多余的,因为您已经将其作为属性,ValidationAttribute并且原始代码会为该属性生成警告ErrorMessage- 您也可以将nameof其用于属性装饰,以使代码中的内容更加紧凑:
我的实现稍微更具体一些,因此如果一个属性是布尔值,我可以指示一个属性是必需的(如果勾选了一个复选框):
[AttributeUsage(AttributeTargets.Property)]
public class RequiredIfTrueAttribute : RequiredAttribute
{
private string PropertyName { get; set; }
public RequiredIfTrueAttribute(string propertyName)
{
PropertyName = propertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
object instance = context.ObjectInstance;
Type type = instance.GetType();
bool.TryParse(type.GetProperty(PropertyName).GetValue(instance)?.ToString(), out bool propertyValue);
if (propertyValue && string.IsNullOrWhiteSpace(value?.ToString()))
{
return new ValidationResult(ErrorMessage);
}
return ValidationResult.Success;
}
}
示例用法:
public bool IsBusinessProfile { get; set; }
[RequiredIfTrue(nameof(IsBusinessProfile), ErrorMessage = "ABN is required for Business Profiles")]
public string Abn { get; set; }
TA贡献1789条经验 获得超8个赞
我建立在 Rob 提供的答案之上。这是一个通用验证器,而不是继承自Required,并且还提供客户端验证。我正在使用.Net Core 3.0
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System;
using System.Collections.Generic;
using System.Text;
namespace System.ComponentModel.DataAnnotations
{
[AttributeUsage(AttributeTargets.Property)]
public class RequiredIfTrueAttribute : ValidationAttribute, IClientModelValidator
{
private string PropertyName { get; set; }
public RequiredIfTrueAttribute(string propertyName)
{
PropertyName = propertyName;
ErrorMessage = "The {0} field is required."; //used if error message is not set on attribute itself
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
object instance = context.ObjectInstance;
Type type = instance.GetType();
bool.TryParse(type.GetProperty(PropertyName).GetValue(instance)?.ToString(), out bool propertyValue);
if (propertyValue && (value == null || string.IsNullOrWhiteSpace(value.ToString())))
{
return new ValidationResult(ErrorMessage);
}
return ValidationResult.Success;
}
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
MergeAttribute(context.Attributes, "data-val-requirediftrue", errorMessage);
}
private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
}
客户端 Javascript
//Custom validation script for the RequiredIfTrue validator
/*
* Note that, jQuery validation registers its rules before the DOM is loaded.
* If you try to register your adapter after the DOM is loaded, your rules will
* not be processed. So wrap it in a self-executing function.
* */
(function ($) {
var $jQval = $.validator;
$jQval.addMethod("requirediftrue",
function (value, element, parameters) {
return value !== "" && value != null;
}
);
var adapters = $jQval.unobtrusive.adapters;
adapters.addBool('requirediftrue');
})(jQuery);
用法
public bool IsSpecialField { get; set; }
[RequiredIfTrue(nameof(IsSpecialField), ErrorMessage="This is my custom error message")]
[Display(Name = "Address 1")]
public string Address1 { get; set; }
[RequiredIfTrue(nameof(IsSpecialField))]
public string City { get; set; }
TA贡献1801条经验 获得超16个赞
另一种更简洁、更通用的方法是实现更通用的属性,而不是特定的“requiredIf”属性,因为您必须为碰巧使用的每种验证类型创建多个自定义属性。
幸运的是,从 .NET Core 2 开始,Microsoft 提供了IPropertyValidationFilter可以在自定义属性上实现的接口。这个接口定义了一个函数ShouldValidateEntry,它允许控制当前条目是否应该被验证;所以这在调用任何验证器之前运行。
框架中已经有一个默认实现,即ValidateNeverAttribute,但是实现您自己的对另一个值进行条件检查是微不足道的:
using System;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
namespace Foo {
// Implementation makes use of the IPropertyValidationFilter interface that allows
// control over whether the attribute (and its children, if relevant) need to be
// validated.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ConditionalValidationAttribute : Attribute, IPropertyValidationFilter {
public string OtherProperty { get; set; }
public object OtherValue { get; set; }
public ConditionalValidationAttribute(string otherProperty, object otherValue) {
OtherProperty = otherProperty;
OtherValue = otherValue;
}
public bool ShouldValidateEntry(ValidationEntry entry, ValidationEntry parentEntry) {
// Default behaviour if no other property is set: continue validation
if (string.IsNullOrWhiteSpace(OtherProperty)) return true;
// Get the property specified by the name. Might not properly work with
// nested properties.
var prop = parentEntry.Metadata.Properties[OtherProperty]?.PropertyGetter?.Invoke(parentEntry.Model);
return prop == OtherValue;
}
}
}
只需使用此属性注释相关属性,任何验证器,以及您自己实现的自定义验证器,只会在必要时调用!
- 3 回答
- 0 关注
- 620 浏览
添加回答
举报