1

我有两节课:

[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。

如果我调用Validate一个新创建的 Country 对象,其中的区域列表为 null,我会收到 StackOverflow 异常。如果我删除 Country.Regions 属性的 [ObjectCollectionValidator(typeof(Region))],一切正常。我猜链接国家 - 地区 - 国家是失败的原因。但是,我不想删除 Regions 集合的验证;从区域中删除 [ObjectValidator] 对我来说都不是一个选项。我可以做些什么来维护所有这些验证属性,没有 StackOverflow 异常?

谢谢,

卢西安

4

3 回答 3

2

前几天我遇到了同样的问题,并且能够通过实现一个自定义验证器类来解决它,该类的功能与 ObjectValidator 的功能非常相似,只是它将被评估的属性的评估延迟到实际的 DoValidate 方法,并且如果属性为空,则不会继续构建验证器。

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

    }
于 2010-01-29T21:02:07.053 回答
1

此错误位于 codeplex 上 EntLib的问题跟踪器中。而且我不确定它是否可以轻松修复。而且我没有找到任何好的解决方法:(。

于 2009-02-23T18:41:06.107 回答
1

诀窍实际上是使用任何ObjectValidatorObjectCollectionValidator属性。您可以自行验证所有对象。这并不总是可行的,但在 O/RM 场景的上下文中尤其有效,其中 O/RM 框架知道哪些实体是新的或已更改的。

看一下这个例子,在使用实体框架将更改提交到数据库之前触发验证:

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'SavingChanges事件。

EntityValidator是一个自定义类,允许使用验证应用程序块验证一组对象。当验证失败时,它会抛出一个ValidationException包装ValidationResults集合的自定义。

static class EntityValidator
{
    public static void Validate(IEnumerable<object> entities)
    {
        ValidationResults[] invalidResults = (
            from entity in entities
            let type = entity.GetType()
            let validator = ValidationFactory.CreateValidator(type)
            let results = validator.Validate(entity)
            where !results.IsValid
            select results).ToArray();

        // Throw an exception when there are invalid results.
        if (invalidResults.Length > 0)
        {
            throw new ValidationException(invalidResults);
        }
    }
}

更多信息在这里

我希望这有帮助。

于 2011-01-28T09:41:40.813 回答