我编写了一个 If-IsRequired 自定义属性来验证一个属性是否包含一个值,具体取决于模型中其他一些属性的值。由于我想让这个属性适用于尽可能多的情况,我想允许开发人员选择利用该属性来提供无限数量的匹配参数。最后,我希望能够强制所有参数都正确匹配。
这是我迄今为止所写的。虽然我目前正在使用字符串数组,但我很乐意使用某种无法工作的集合。此外,我现在需要支持当前的属性定义并创建一个包含比较运算符的新重载。除了假设所有比较都使用等于完成的原始定义之外,这将允许我进行小于、大于和不相等的比较。
/// <summary>
/// A custom attribute that checks the value of other properties passed to it in order to
/// determine if the property this attribute is bound to should be required.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class IsPropertyRequiredAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "{0} is required.";
public string[] _selectionContextNames { get; private set; }
public string[] _expectedValues { get; private set; }
/// <summary>
/// Creates a new instance of the IsPropertyRequriedAttribute.
/// </summary>
/// <param name="SelectionContextNames">The name of the other property in the view model to check the value of.</param>
/// <param name="ExpectedValues">The expected value of the other property in the view model in order to determine if the current property the attribute is bound to should be required.</param>
public IsPropertyRequiredAttribute(string[] SelectionContextNames, string ExpectedValues)
: base(DefaultErrorMessage)
{
_selectionContextNames = SelectionContextNames;
_expectedValues = ExpectedValues;
}
public override bool IsValid(object value)
{
if (_selectionContextNames == null || _expectedValues == null)
{
if (_selectionContextNames != null || _expectedValues != null)
{
string paramName;
if (_selectionContextNames == null)
{
paramName = "ExpectedValues";
}
else
{
paramName = "SelectionContextNames";
}
throw new ArgumentException("Key/Value pairs need to match for IsPropertyRequired.", paramName);
}
}
else if (_selectionContextNames.Length != _expectedValues.Length)
{
string paramName;
if (_selectionContextNames.Length < _expectedValues.Length)
{
paramName = "ExpectedValues";
}
else
{
paramName = "SelectionContextNames";
}
throw new ArgumentException("Parameter element counts need to match for IsPropertyRequired.", paramName);
}
bool paramsValid = true;
if (_selectionContextName!= null)
{
for (int i = 0; i < _selectionContextName.Length; i++)
{
string paramValue = HttpContext.Current.Request[_selectionContextName[i]];
if (_expectedValue[i] != paramValue)
{
paramsValid = false;
}
}
if (paramsValid == true)
{
return (value != null);
}
else
{
return true;
}
}
else
{
return true;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(DefaultErrorMessage, name);
}
}
虽然使用属性来装饰属性将取决于属性的定义方式,这是我目前实现的(也可能会改进):
[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4"}, new string[] {"1", "2", "3", "4"})]
public string SomeText { get; set; }
另外,我想尽可能地防止以下装饰的发生:
[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4", "prop5withoutvalue"}, new string[] {"1", "2", "3", "4"})]
public string SomeOtherText { get; set; }
并且使用包含比较运算符作为参数的新重载,我们现在可以拥有:
[IsPropertyRequired(new string[] {"prop1", "prop2", "prop3", "prop4"}, new string[] {"==", ">", "!=", "<="}, new string[] {"1", "2", "3", "4"})]
public string SomeComparisonText { get; set; }