1

私は2つのクラスを持っています:

[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 - October 2008/.NET 3.5 SP1/Vista を使用しています。

地域のリストとして null を使用して新しく作成された Country オブジェクトを呼び出すValidateと、StackOverflow 例外が発生します。Country.Regions プロパティの [ObjectCollectionValidator(typeof(Region))] を削除すると、すべて正常に動作します。国 - 地域 - 国というリンクが失敗の原因だと思います。ただし、Regions コレクションの検証を削除したくありません。領域から [ObjectValidator] を削除することも、私にとってはオプションではありません。StackOverflow 例外なしで、これらすべての検証属性を維持するためにできることはありますか?

ありがとう、

ルシアン

4

3 に答える 3

2

つい先日も同じ問題に遭遇しましたが、実際の DoValidate メソッドまで評価されるプロパティの評価を遅らせることを除いて、ObjectValidator とほぼ同じように機能するカスタム バリデータ クラスを実装することで、問題を解決することができました。プロパティが 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; }
        }

    }
于 2010-01-29T21:02:07.053 に答える
1

このバグは、codeplex の EntLib の問題トラッカーにあります。そして、それが簡単に修正できるかどうかはわかりません。そして、私はそれに対する良い回避策を見つけられませんでした:(。

于 2009-02-23T18:41:06.107 に答える
1

秘訣は、実際にはand属性を使用しないことです。すべてのオブジェクトを自分で検証できます。これは常に機能するとは限りませんが、O/RM フレームワークが新しいエンティティまたは変更されたエンティティを認識している O/RM シナリオのコンテキストでは特にうまく機能します。ObjectValidatorObjectCollectionValidator

たとえば、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コードはのSavingChangesイベントにフックします。

EntityValidator、Validation Application Block を使用してオブジェクトのグループを検証できるカスタム クラスです。検証が失敗すると、コレクション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 に答える