List of Business Rules not static

List of Business Rules not static

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


david.wendelken posted on Monday, February 04, 2008

Darn. :(

I've been using some extensions to CSLA that make the list of business rules public.  (Not just the broken rules, but the rules themselves).

I've got a nice little button on the UI that opens up a panel that displays the business rules for an object.  Works sweet! :)

I don't use instance rules, just type rules, as I believe instance rules are just poorly specified type rules, so in theory my list of rules could be static.  Regardless, the list of type rules per class could be static.

Here comes the rub.  If I go to a maintenance screen for the object, and there are no objects yet, the list that contains those objects is empty.   My publically available list of type rules IS NOT static because II depend upon the built-in framework components to get my list of rules, and they are not static.  This means that I cannot tell someone what the rules are until after they create an object! Needless to say, that's not how I like to conduct business!  (Example: I'll just start building this house for you, THEN tell you what the rules are for paying for one.)

In tracking down the problem, it appears that the list of Type rules is initialized in the constructor for the object.  I think it should be made available as a public static property.  Whoever asks first - the constructor or the property - should cause the static list of type rules to be instantiated.

In effect, ValidationRules.GetRuleDescriptions would be copied and modified to become ValidationRules.GetTypeRuleDescriptions, which would be a public static method that returns a string[].

Comments?

As a work around, I have the UI check to see if the list is empty.  If so, it creates a throw-away list, adds a new object to the list, asks for the rules, and then disposes of the list.  Dorky, but it works.

 

vdhant replied on Monday, February 04, 2008

What you are describing sounds very similar to the changes that Rock made to the Auth engine for 3.5. In the Auth engine now there are several static methods that you can call to find out various bits and pieces. This intern looks to see if the rules for this type have been loaded. Now this is where you would normal run into trouble with having to create an instance of the object first. But the new system to get around this looks for a static method on the type in question which loads up the auth rules for this type. The result here means that you don’t need to create the object to find out the auth rules.

 

It makes sense that a similar thing be done for the validation engine to help in situations like yours.

The only disadvantage with the system is that because .net doesn’t have the concept of interfaces that declare static methods, the system uses reflection to see if the static method exists. Hence it is by convention that one has to implement this static method in order of the system to pickup the rules before the a type instance is created.

 

This may be a question that Rocky may have to answer, but I am not sure how this pattern handles inherited business classes (like lets say I have employees which has a sub type of Manager and another of Pleb) in regards to the static methods and the fact that within each sub class one may want to define rules that need to be applied???

 

Hope that helps
Anthony


RockfordLhotka replied on Monday, February 04, 2008

Putting values into static fields has turned out to be a much harder thing than I'd ever imagined. The reason is due to the rules governing when static fields are initialized, and the cost of putting a static constructor in a class.

Trusting people like Brad Abrams and others who should really know, I am accepting their contention that a static ctor should be avoided thanks to all the extra code the compiler must inject all over the place for it to work properly. So static ctors are out.

But static fields are only initialized when a static field in the specific type is accessed.

So if you have inheritance in the mix, the intermediate types in the inheritance hierarchy aren't necessarily initialized when you think they would be. This problem was discovered with the new RegisterProperty() technique, and the solution is rather a hack - and still only works if an instance of the object is actually created.

I didn't encounter this problem with the object level auth rules, because I directly use reflection to invoke the AddObjectAuthorizationRules() method. I did that because there was no way to force static code to run in the business class. Even a static ctor doesn't help with this problem, because of the rules governing when a static ctor runs. They only run when a static field is accessed or an instance of the object is created. Since I can't guarantee that you'll access (or even declare) a static field, the only way to force the cctor to run would have been to create an instance of the object - and the whole point of using the static fields was to avoid that in the first place...

Problems that seem simple on the surface have been turning out to be really complex right under that veneer.

vdhant replied on Monday, February 04, 2008

"I didn't encounter this problem with the object level auth rules, because I directly use reflection to invoke the AddObjectAuthorizationRules() method."

I realise that the static initialisation mightn't be a problem with the above but what i am referring to is that inheritance is going to be an issue. Using the example i had before, if i want to before auth rules in Employee i would need to create a static method AddObjectAuthorizationRules. If in manager i want to have these rules plus more how do i get on. See below:

    public class Employee
    {
        public static void AddObjectAuthorizationRules()
        {
            //Rules that all Employees should have (should be total 2 rules is only 2)
            AuthorizationRules.AllowDelete(typeof(Employee), "ProjectManager");
            AuthorizationRules.AllowDelete(typeof(Employee), "Administrator");
        }
    }

    public class Manager : Employee
    {
        public static void AddObjectAuthorizationRules()
        {
            //Rules that all Managers should have (should be total 4 rules but only 2)
            AuthorizationRules.AllowCreate(typeof(Manager), "ProjectManager");
            AuthorizationRules.AllowEdit(typeof(Manager), "ProjectManager");
        }
    }


If i was reading through the part where you are using reflection to invoke AddObjectAuthorizationRules correctly, to get around this problem something like the following should be possible (where the type is passed in by the code conducing the reflection):

    public class Employee
    {
        public static void AddObjectAuthorizationRules(Type currentType)
        {
            AuthorizationRules.AllowDelete(currentType, "ProjectManager");
            AuthorizationRules.AllowDelete(currentType, "Administrator");
        }
    }

    public class Manager : Employee
    {
        public static void AddObjectAuthorizationRules(Type currentType)
        {
            Employee.AddObjectAuthorizationRules(currentType);

            AuthorizationRules.AllowCreate(currentType, "ProjectManager");
            AuthorizationRules.AllowEdit(currentType, "ProjectManager");
        }
    }

Also getting back to the original question that this post was about, would it not make sense to allow this same sort of static processing for the validation rules as we are doing here with the auth rules?
Anthony

david.wendelken replied on Tuesday, February 05, 2008

Getting the "type" at runtime in a static method was not easy.  That's because most methods that return the type supply a type for an object, and in a static method, you haven't got an object, you've got a class.

I said "most" because I didn't find a method that worked with a class in a static method and I'm hoping:

  1. there is such a method, and
  2. someone will tell me what it is!

I got around the problem by placing constants in my generated classes that supplied the values I needed.  I think that's a stupid thing to have to do, but it was the best solution I could find that worked.  :(

david.wendelken replied on Thursday, February 07, 2008

Based upon more testing, I've ditched the static CanAdd methods (etc.) and replaced them with non-static methods for my list classes.

My base list class has virtual methods that return true and I override them as necessary.

Basically, the idea (as I understood it) behind having the static methods was to make it easy for the UI programmer to ask whether a given functionality was ok to activate. 

I realized that it wasn't that big a deal to instantiate the list object (empty if need be) and then have the UI call those methods. 

That's a small price to pay (at least as I've experienced it so far!) for the coding simplicity and run-time efficiency of not having to do reflection in my genericized UI page objects. 

RockfordLhotka replied on Tuesday, February 05, 2008

Note that I’m not doing anything different for per-property auth rules than in the past. So validation and authorization continue to work as always. I just added per-object auth rules so you don’t have to write (by convention) the static GetXYZ methods. I don’t think I’ve removed any capability you had before, just formalized something most people were doing by convention. In other words, you are correct that inheritance isn’t really supported – but it wasn’t before either. Nor is there a clear solution to the issue, because you can’t override static methods, and if we really want this to work at the static level then options are very limited.

 

Rocky

 

From: vdhant [mailto:cslanet@lhotka.net]
Sent: Monday, February 04, 2008 9:34 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] List of Business Rules not static

 

"I didn't encounter this problem with the object level auth rules, because I directly use reflection to invoke the AddObjectAuthorizationRules() method."

I realise that the static initialisation mightn't be a problem with the above but what i am referring to is that inheritance is going to be an issue. Using the example i had before, if i want to before auth rules in Employee i would need to create a static method AddObjectAuthorizationRules. If in manager i want to have these rules plus more how do i get on. See below:

    public class Employee
    {
        public static void AddObjectAuthorizationRules()
        {
            //Rules that all Employees should have (should be total 2 rules is only 2)
            AuthorizationRules.AllowDelete(typeof(Employee), "ProjectManager");
            AuthorizationRules.AllowDelete(typeof(Employee), "Administrator");
        }
    }

    public class Manager : Employee
    {
        public static void AddObjectAuthorizationRules()
        {
            //Rules that all Managers should have (should be total 4 rules but only 2)
            AuthorizationRules.AllowCreate(typeof(Manager), "ProjectManager");
            AuthorizationRules.AllowEdit(typeof(Manager), "ProjectManager");
        }
    }

 

If i was reading through the part where you are using reflection to invoke AddObjectAuthorizationRules correctly, to get around this problem something like the following should be possible (where the type is passed in by the code conducing the reflection):

    public class Employee
    {
        public static void AddObjectAuthorizationRules(Type currentType)
        {
            AuthorizationRules.AllowDelete(currentType, "ProjectManager");
            AuthorizationRules.AllowDelete(currentType, "Administrator");
        }
    }

    public class Manager : Employee
    {
        public static void AddObjectAuthorizationRules(Type currentType)
        {
            Employee.AddObjectAuthorizationRules(currentType);

            AuthorizationRules.AllowCreate(currentType, "ProjectManager");
            AuthorizationRules.AllowEdit(currentType, "ProjectManager");
        }
    }

Also getting back to the original question that this post was about, would it not make sense to allow this same sort of static processing for the validation rules as we are doing here with the auth rules?
Anthony



Copyright (c) Marimer LLC