Is it possible to have CSLA purge the per-type validation rules cache?

Is it possible to have CSLA purge the per-type validation rules cache?

Old forum URL: forums.lhotka.net/forums/t/5196.aspx


rsbaker0 posted on Tuesday, August 05, 2008

The subject pretty much says it all.

Some of the "per type" validation rules we have been creating are derived from configuration type functions (some of which might even change the database schema). So, when the user performs one of these operations, I'd like to have CSLA clear it's rules caches so that AddBusinessRules() gets called again for each object.

Granted, this is only happens when major configuration changes are made and I could force the user to exit and restart the application, but that doesn't seem especially friendly.

ajj3085 replied on Tuesday, August 05, 2008

It may not be friendly, but its probably the easiest and most reliable way to handle this situation.  FWIW, this is exactly why Windows doesn't "see" group membership changes to your domain logon without logging off then on again, because trying to "figure out" the changes and how to apply them is simply too difficult.

rsbaker0 replied on Tuesday, August 05, 2008

Well, for example, our application supports changing the database connection. Are you suggesting that I should have to exit and restart the application just to connect to a different database?

It will be a hard pill for our existing application users to swallow -- they "upgrade" to the new version of our application and are now asked to exit and restart for changes that didn't require a restart previously.

This particular case didn't seem that difficult, it's just the CSLA has the classes marked as internal and doesn't allow access or clearing of the static validation rules cache.

ajj3085 replied on Tuesday, August 05, 2008

Well your question was about clearing business rules, not changing connection strings. 

If you want to go down that path, you could probably do so.. but I have a feeling it will lead to many headaches later.

rsbaker0 replied on Tuesday, August 05, 2008

Yes, but our per-type rules can be data dependent -- they are static for a particular database, but if I change the database I'm connecting to, I need to reset the rules also (this was just an example of a configuration change -- sorry if I confused this issue).

 

ajj3085 replied on Tuesday, August 05, 2008

Oh I see..

Well that should be doable, but the data upon which the rules depend should probably be cached somewhere, and when the rule runs it can evaluate the case.  It "reset" you could clear this cache of data, and have it lazy loaded so that the next time a rule runs the rule data gets reloaded as well.

If the rule should be completely ignore, that could be handled in a similar way with a flag that indicates if the rule should really run.

rsbaker0 replied on Tuesday, August 05, 2008

In theory, you are correct.

However, in practice, it's not quite so easy. For example (ugh), some of the referential integrity constraints in our application are dynamic (a customer can say a certain piece of data in the application must come from table X).

So, our BB subclass implements a generalized referential integrity business rule, one rule per active referential integrity constraint.

So, when I switch from one database to another, a previous rule in the list may no longer be valid, or I might need to add rules that weren't there before.

(It's actually worse than this -- the customer can add their own custom fields to our schema that have similar constraints, but this illustrates the problem).

RockfordLhotka replied on Tuesday, August 05, 2008

I don't think clearing the cache would be that big a deal - a static method on ValidationRules to invoke one on SharedValidationRulesManager that locks, then clears the dictionary.

There are two possible complications I can see.

First, if you have objects accessing any rules at that time there could be odd race conditions. Fixing them would require more locking, and that'd have an overall negative perf impact. So a pre-condition of you calling this "clear" method would probably involve YOU making sure no code anywhere, on any thread, is calling any validation rules.

Second, if you have object instances with broken rules, and you change the rules out from under them, you'd never be able to unbreak those rules. Those instances would be permanently invalid. So a pre-condition of you calling this "clear" method would involve YOU making sure you have no object instances, on any thread, that is currently invalid.

On a smart client I could see that maybe working. But on a server this would be virtually impossible.

So my worry is that if I add this capability, you'll enjoy it, and I'll have a permanent support problem as people's objects get confused on their app servers.

rsbaker0 replied on Wednesday, August 06, 2008

I agree it's a potential can of worms, but I did envision using this mainly in a "smart client" environment, and I certainly don't see letting clients change the database connection associated with an application server -- that would be limited to some sort of server side configuration or setup procedure.

In the application we are porting from, when we change the database connection, we destroy any open objects and make the user log in again. Doing this in our CSLA application has proved somewhat daunting. What I have done so far is to invent an class-level attribute that specifies the name of a static "database reset" method (and optional priority) to be invoked when the database connection is changed. To reset the database, I collect all the resetters by enumerating types that have the attribute, sort them by priority and invoke their reset procedure. (For efficiency, the assembly must be be tagged with a variant of same attribute so I don't look through non-applicable assemblies)

rsbaker0 replied on Wednesday, August 06, 2008

Horrors!  :)

I did this just as an exercise -- certainly not advisable...

 

        public static void ResetValidationRulesCache()
        {
            // Reflect on CSLA to clear the validation rules cache...
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                AssemblyName name = assembly.GetName();

                if (name.Name.Equals("CSLA", StringComparison.OrdinalIgnoreCase))
                {
                    Type type = assembly.GetType("Csla.Validation.SharedValidationRules");
                    if (type != null)
                    {
                        FieldInfo f = type.GetField("_managers", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public);
                        if (f != null)
                        {
                            object o = f.GetValue(null);
                            if (o != null)
                            {
                                MethodCaller.CallMethodIfImplemented(o,
                                    "Clear");
                            }
                        }
                    }
                    break;
                }
           }
        }

ajj3085 replied on Wednesday, August 06, 2008

So... does it work? Smile [:)]

RockfordLhotka replied on Wednesday, August 06, 2008

I think your best bet might really be to create a method that uses reflection to call Clear() on the _managers static field in SharedValidationRules.

 

The consequences of me creating a public method that could be called without someone understanding all the nasty ramifications is just too much I think.

 

Rocky

 

 

From: rsbaker0 [mailto:cslanet@lhotka.net]
Sent: Wednesday, August 06, 2008 7:09 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Is it possible to have CSLA purge the per-type validation rules cache?

 

I agree it's a potential can of worms, but I did envision using this mainly in a "smart client" environment, and I certainly don't see letting clients change the database connection associated with an application server -- that would be limited to some sort of server side configuration or setup procedure.

In the application we are porting from, when we change the database connection, we destroy any open objects and make the user log in again. Doing this in our CSLA application has proved somewhat daunting. What I have done so far is to invent an class-level attribute that specifies the name of a static "database reset" method (and optional priority) to be invoked when the database connection is changed. To reset the database, I collect all the resetters by enumerating types that have the attribute, sort them by priority and invoke their reset procedure. (For efficiency, the assembly must be be tagged with a variant of same attribute so I don't look through non-applicable assemblies)



rsbaker0 replied on Wednesday, August 06, 2008

^^^^^^^^

That was exactly what I did in my previous post, mainly just to see if I could.  :)

However, it's not just a can of worms, it's a 55 gallon drum, or maybe even an oil tanker's worth.

My reflecting method that clears the rule cache indeed works, but then I discovered all my classes were holding their own internal static reference to their list of referential integrity rules. Oops, something else to have to worry about clearing, etc.

It turns that that it may be fairly easy to have a client restart itself, so I'm going to investigate that route.

 

ajj3085 replied on Wednesday, August 06, 2008

Not sure how you're deploying, but if you're using ClickOnce, there is functionality built in to do that.. but I don't know if it only works after an update or not.

RockfordLhotka replied on Wednesday, August 06, 2008

Oh, good point. I’d forgotten about that. Lots and lots of caching to minimize perf costs….

 

Rocky

 

 

From: rsbaker0 [mailto:cslanet@lhotka.net]
Sent: Wednesday, August 06, 2008 1:41 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Is it possible to have CSLA purge the per-type validation rules cache?

 

^^^^^^^^

That was exactly what I did in my previous post, mainly just to see if I could.  :)

However, it's not just a can of worms, it's a 55 gallon drum, or maybe even oil tanker's worth.

My reflecting method that clears the rule cache indeed works, but then I discovered all my classes were holding their own internal static reference to their list of referential integrity rules. Oops, something else to have to worry about clearing, etc. It turns that that it may be fairly easy to have a client restart itself, so I'm going to investigate that route.

 



vdhant replied on Friday, August 08, 2008

I see this need to purge lists at the type level being relevant for all components where the data is stored statically. Particularly for those loading data from a dynamic source.

rsbaker0 replied on Friday, August 08, 2008

vdhant:
I see this need to purge lists at the type level being relevant for all components where the data is stored statically. Particularly for those loading data from a dynamic source.

I had a system in place for handling this. I invented an attribute that I could tag a class that stored static data that should be purged in the event of a "reset", with the attribute data providing the name of the reset method to be called.

When doing the reset, I simply interrogated all the classes tagged with the attribute and called their reset method. It worked fine.

It's not without risk, though. It's easy to overlook something, and I had to introduce the concept of a priority because some of the classes referenced each other and it was important that some data be cleared (or reloaded) before others.

Anyway, it's viable only in a 2-tier situation anyway. As soon as you introduce an application server, both restarting and purging seem problematic.

JoeFallon1 replied on Friday, August 08, 2008

I vote for a client re-start over trying to purge all the caches.

Joe

 

ajj3085 replied on Friday, August 08, 2008

Again, I agree.  It's quite a bit of effort to do this correctly, and I would think it'd be an on-going source of problems down the road if not done very carefully.  That's why I pointed out that MS forces you to logoff to before any security settings are seen by Windows when your AD account changes. 

The benefits to the user (not needing to restart) need to be weighed against the cost of initial coding to handle this, ongoing maintenance, and user unhappiness caused by bugs when it's not done correctly.

Copyright (c) Marimer LLC