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.
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.
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).
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).
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.
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)
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;
}
}
}
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)
^^^^^^^^
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.
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: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.
I vote for a client re-start over trying to purge all the caches.
Joe
Copyright (c) Marimer LLC