Can we apply our own PostSharp aspects to model... in order to do things like logging or validation? I'm assuming that DO4's aspects would need to be weaved after our custom aspects are woven, if we want to implement within our custom aspects anything that requires data access.

Will DO4 be compatible with things like ValidationAspects (http://validationaspects.codeplex.com/)? What I like about VA is that validation can be modified through changes in XAML config file instead of requiring changes to code + recompile.

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Jul 30 '09 at 20:40

ara's gravatar image

ara
395868791


One Answer:

Yes, you can - we don't do anything preventing you from this. But I'd recommend to use our own validation framework, or at least check the priority of aspects applied by your own.

Why? Let's start from a simple example:

Here is decompiled code of typical persistent property w/o any validation aspects:

[Field(Length=100)]
public string Street
{
    [CompilerGenerated]
    get
    {
        return this.GetFieldValue<string>("Street");
    }
    [CompilerGenerated]
    set
    {
        this.SetFieldValue<string>("Street", value);
    }
}

Now let's take a look on decompiled code of a similar property, but with applied validation aspect:

[Field]
public string Phone
{
    [CompilerGenerated]
    get
    {
        return this.GetFieldValue<string>("Phone");
    }
    [CompilerGenerated]
    set
    {
        object obj2;
        try
        {
            MethodExecutionEventArgs args;
            obj2 = ~PostSharp~Laos~Implementation.TransactionalAspect~74.OnEntry(this);
            try
            {
                object[] arguments = new object[] { value };
                args = new MethodExecutionEventArgs(~PostSharp~Laos~Implementation.~targetMethod~99, this, arguments);
                ~PostSharp~Laos~Implementation.ImplementPropertyConstraintAspect~99.OnEntry(args);
                if (args.FlowBehavior != FlowBehavior.Return)
                {
                    this.SetFieldValue<string>("Phone", value);
                    ~PostSharp~Laos~Implementation.ImplementPropertyConstraintAspect~99.OnSuccess(args);
                }
            }
            catch (Exception exception)
            {
                args.Exception = exception;
                ~PostSharp~Laos~Implementation.ImplementPropertyConstraintAspect~99.OnException(args);
                switch (args.FlowBehavior)
                {
                    case FlowBehavior.Continue:
                    case FlowBehavior.Return:
                        goto Label_00CE;
                }
                throw;
            }
            finally
            {
                ~PostSharp~Laos~Implementation.ImplementPropertyConstraintAspect~99.OnExit(args);
            }
        Label_00CE:
            ~PostSharp~Laos~Implementation.TransactionalAspect~74.OnSuccess(this, obj2);
        }
        finally
        {
            ~PostSharp~Laos~Implementation.TransactionalAspect~74.OnExit(this, obj2);
        }
    }
}

Its original code was:

[Field]
    [PhoneNumberConstraint]
    public string Phone { get; set; }

As you see, if our own property constraint aspects are applied, property setter is automatically wrapped by a TransactionalAspect. So before any validation logic is executed, it will activate a Session and open a transaction, if this is necessary; thus logic in PropertyConstraintAspect may fully rely on this fact.

Notes:

  • Same does not happen for regular properties just because SetFieldValue<t> and GetFieldValue<t> are already transactional

  • Later we'll switch from string-based property resolution to index-based one (it will be noticeably faster), see http://code.google.com/p/dataobjectsdot ... tail?id=75

If you want to inject your own validation aspects, you must properly prioritize them relatively to TransactionalAspect.AspectPriority ( = StorageAspectPriority.Transactional = -200000). Moreover, our own aspect injection framework won't automatically inject TransactionalAspect for persistent properties decorated just by your own aspects. To achieve this, you must decorate them by [AspectBehavior] attribute.

Conclusion:

Our own validation framework is likely more ready to be used with validation related to RDBMS, and I recommend you to stick to it. Few more facts:

  1. It ensures that in general all the graph of objects must be in consistent state

  2. Any our own validation-aware object must provide IValidationAware.OnValidate method. We provide this method in Persistent, its current implementation is:

    if (!CanBeValidated) // True for Structures which aren't bound to entities return; this.CheckConstraints(); // Ensures all PropertyConstraintAspects will be executed // CheckConstraints is an extension method provided by Integrity OnValidate(); // Runs custom validation logic: this OnValidate can be overriden

So as you see, this approach allows to validate any object at any point of time.

  1. Framework is aware sometimes pasts of the graph can be in inconsistent state (= particular validation may fail). Use InconsistentRegion.Open method to create a region where validation is disabled. Any validation-related calls will be registered for later execution in this case - actually we register either the whole object, or its properties to validate.

So in fact, you can temporarily turn off the validation. But this won't allow you to violate its rules, since they would be anyway applied later.

Why we simply don't disable the whole validation for the duration of transactions (many others do ~ this)? That's because:

  • It's always desirable to get an exception "in place" (i.e. on change), rather than to get a bulk of them on commit. First case immediately points to the source of the problem, but the last one provides only limited information (e.g. property name) about it.

  • In real life the size of validation queue is ~ proportional to the size of transaction. Since some transactions can be really long, generally it can't be stored in RAM. That's why we avoid this path and allow you to decide where it's possible to "flush" it.

  • Inconsistency regions are automatically checked to be closed on completion of any transaction (ValidationContext.IsConsistent must be true). This ensures only consistent data can be committed.

  • As I've shown above, our own validation aspects are properly injected into persistent property setter (taking into account possible opening of transaction for the whole setter).

P.S. If you'll find a feature missing in it, please write to us. We're ready to make it better ;)


Forgot to add: in above post I was talking only about validation of persistent state. It is almost fully based on our Integrity.Validation framework - the only "customizations" we've made in Storage are:

  • We explicitly check if inconsistency regions are closed @ commit

  • We ensure TransactionalAspects are automatically applied to persistent properties with attached validators (constraints).

That's it. So the framework is very generic, and you can use it everywhere where you want (i.e. independently from Xtensive.Storage).

On the other hand, we don't push you to do this - i.e. no other product features rely on it.


Concerning extracting validation logic to XAML:

  • Actually you can achieve this with ease without aspects: override Persistent.OnSettingFieldValue + likely, OnValidate and do what you want.

  • On the other hand, I don't believe much in "too distant" validation: the more complex its logic, the slower it is. Although may happen quite frequently.

answered Jul 31 '09 at 05:49

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

Fantastic response, Alex. Thank you.

(Jul 31 '09 at 05:49) ara ara's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×574

Asked: Jul 30 '09 at 20:40

Seen: 3,084 times

Last updated: Jul 30 '09 at 20:40

powered by OSQA