我有两个班级:
[HasSelfValidation]
class Country : DomainObject
{
[NotNullValidator]
[StringLengthValidator(2, 10)]
public string Name { get; set; }
[ObjectCollectionValidator(typeof(Region))]
public List<Region> Regions { get; set; }
}
和
[HasSelfValidation]
class Region : DomainObject
{
[NotNullValidator]
[ObjectValidator]
public Country Country { get; set; }
[NotNullValidator]
[StringLengthValidator(2, 20)]
public string Name { get; set; }
}
DomainObject有方法:
public virtual ValidationResults Validate()
{
Validator validator =
ValidationFactory.CreateValidator(this.GetType());
ValidationResults results = new ValidationResults();
validator.Validate(this, results);
return results;
}
我正在使用Microsoft Enterprise Library 4.1 - 2008年10月/ .NET 3.5 SP1 / Vista。
如果我为新创建的Country对象调用Validate
而没有null作为区域列表,我得到一个StackOverflow异常。如果我删除Country.Regions属性的[ObjectCollectionValidator(typeof(Region))],一切正常。我想链接国家 - 地区 - 国家是失败的原因。但是,我不想删除Regions集合的验证;既不从区域中删除[ObjectValidator]也是我的选择。有什么我可以做的来维护所有这些验证属性,没有StackOverflow异常吗?
谢谢,
卢西恩
答案 0 :(得分:1)
此错误是codeplex上的EntLib的in issue tracker。而且我不确定它是否可以轻松修复。我没有找到任何好的解决方法:(。
答案 1 :(得分:1)
我前几天遇到了同样的问题,并且能够通过实现一个自定义验证器类来实现它,其功能与ObjectValidator相同,只是它延迟了对被评估属性的评估,直到实际的DoValidate方法,如果属性为null,则不会继续构建验证器。
using System;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Properties;
namespace Microsoft.Practices.EnterpriseLibrary.Validation.Validators
{
/// <summary>
/// Performs validation on objects by applying the validation rules specified for a supplied type at RUNTIME.
/// This validator can be used to get past StackOverflowExceptions that can be thrown as a result of the design
/// of the ObjectValidator attribute
/// </summary>
/// <seealso cref="ValidationFactory"/>
public class RuntimeObjectValidator : Validator
{
private Type targetType;
private string targetRuleset;
/// <summary>
/// <para>Initializes a new instance of the <see cref="RuntimeObjectValidator"/> for a target type.</para>
/// </summary>
/// <param name="targetType">The target type</param>
/// <remarks>
/// The default ruleset for <paramref name="targetType"/> will be used.
/// </remarks>
/// <exception cref="ArgumentNullException">when <paramref name="targetType"/> is <see langword="null"/>.</exception>
public RuntimeObjectValidator(Type targetType)
: this(targetType, string.Empty)
{ }
/// <summary>
/// <para>Initializes a new instance of the <see cref="RuntimeObjectValidator"/> for a target type
/// using the supplied ruleset.</para>
/// </summary>
/// <param name="targetType">The target type</param>
/// <param name="targetRuleset">The ruleset to use.</param>
/// <exception cref="ArgumentNullException">when <paramref name="targetType"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">when <paramref name="targetRuleset"/> is <see langword="null"/>.</exception>
public RuntimeObjectValidator(Type targetType, string targetRuleset)
: base(null, null)
{
if (targetType == null)
{
throw new ArgumentNullException("targetType");
}
if (targetRuleset == null)
{
throw new ArgumentNullException("targetRuleset");
}
this.targetType = targetType;
this.targetRuleset = targetRuleset;
}
/// <summary>
/// Validates by applying the validation rules for the target type specified for the receiver.
/// </summary>
/// <param name="objectToValidate">The object to validate.</param>
/// <param name="currentTarget">The object on the behalf of which the validation is performed.</param>
/// <param name="key">The key that identifies the source of <paramref name="objectToValidate"/>.</param>
/// <param name="validationResults">The validation results to which the outcome of the validation should be stored.</param>
/// <remarks>
/// If <paramref name="objectToValidate"/> is <see langword="null"/> validation is ignored.
/// <para/>
/// A referece to an instance of a type not compatible with the configured target type
/// causes a validation failure.
/// </remarks>
protected internal override void DoValidate(object objectToValidate,
object currentTarget,
string key,
ValidationResults validationResults)
{
if (objectToValidate != null)
{
if (this.targetType.IsAssignableFrom(objectToValidate.GetType()))
{
validationResults.AddAllResults(
ValidationFactory.CreateValidator(objectToValidate.GetType()).Validate(objectToValidate));
}
else
{
// unlikely
this.LogValidationResult(validationResults, Resources.ObjectValidatorInvalidTargetType, currentTarget, key);
}
}
}
/// <summary>
/// Gets the message template to use when logging results no message is supplied.
/// </summary>
protected override string DefaultMessageTemplate
{
get { return null; }
}
#region test only properties
internal Type TargetType
{
get { return this.targetType; }
}
internal string TargetRuleset
{
get { return this.targetRuleset; }
}
#endregion
}
}
当然,您还需要创建一个RuntimeObjectValidatorAttribute类,以便您可以这样做:
public class AClassThatReferencesItself
{
private AClassThatReferencesItself _other;
private string myString;
[NotNullValidator]
public string MyString
{
get { return myString; }
set { myString = value; }
}
[RuntimeObjectValidator]
[NotNullValidator]
public AClassThatReferencesItself Other
{
get { return _other; }
set { _other = value; }
}
}
答案 2 :(得分:1)
诀窍实际上是不使用任何ObjectValidator
和ObjectCollectionValidator
属性。您可以通过自己验证所有对象。这并不总是可行,但在O / RM场景的上下文中尤其有效,其中O / RM框架知道哪些实体是新的或已经改变。
在此示例中查找实例,其中在使用Entity Framework将更改提交到数据库之前触发验证:
public partial class NorthwindEntities
{
partial void OnContextCreated()
{
// Adding validation support when saving.
this.SavingChanges += (sender, e) =>
{
// Throws an exception when invalid.
EntityValidator.Validate(
this.GetChangedEntities());
}
}
private IEnumerable<object> GetChangedEntities()
{
const EntityState AddedAndModified =
EntityState.Added | EntityState.Modified;
var entries = this.ObjectStateManager
.GetObjectStateEntries(AddedAndModified);
return
from entry in entries
where entry.Entity != null
select entry.Entity;
}
}
代码挂钩到ObjectContext
的{{1}}事件。
SavingChanges
是一个自定义类,允许使用验证应用程序块验证一组对象。验证失败时,会抛出一个包装EntityValidator
集合的自定义ValidationException
。
ValidationResults
更多信息here。
我希望这会有所帮助。