Force initialization of per-type properties

Force initialization of per-type properties

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


crackity_jones666 posted on Monday, December 20, 2010

Hi....

I would like to be able to access some per-type properties of an entity on the constructor of a view-model.

Let's say I have a Silverlight ViewModel that needs to access a static property (so per-type property) on a model.  This property is initialized throught an overrides of the AddBusinessRules method.

This method (AddBusinessRules)  is not called until the model (first instance of my business entity) is loaded.  I tried to publish a new static method that would initialize the private static attribute but with no success....

  public static void DoInitialize()
        {
                     _forceInit = 1;
        }

To achieve my goal, I needed to call the new() constructor of my business entity as the first line on my constructor to initialize the entity
 protected MyViewModel(IEventAggregator eventAggregator, IModuleManager moduleManager)
            : base(eventAggregator, moduleManager)
        {

            var e = new MyEntity();
Some kind of a hack...  I don't really like this.  Is there another way to initialize the per-type attributes?
Thanks in advance!

RockfordLhotka replied on Monday, December 20, 2010

The _forceInit trick turns out to not work in real life in any case, because Silverlight 4 added more compiler optimizations that ultimately optimize away something as straightforward as setting the value to 1.

So CSLA 3.8 actually has code to reflect against the public static fields of each type to force the initialization. This is why I now recommend the static PropertyInfo<T> fields all be public on business types - so they can be auto-initialized by CSLA.

Then you just need to touch the field manager for a type, and the field manager will make sure that type's static fields are initialized.

crackity_jones666 replied on Monday, December 20, 2010

I don't want to use a PropertyInfo because I don't want my static property to be serialized by the MobileFormatter.  I want it to be initialized JIT just like the BusinessRules collection.

I was feeling wild, so I'm trying to implement a separate set of Business Rules(I called them the Execution Rules, it's basically a per-type list of boolean function (Func<TEntity, bool>) that an override of the CanExecuteMethod calls.  We think that the CanExecuteMethod can do a whole more than what it does actually...

It allows me to extends the concept of ValidationRules used by persistancy methods to any other method.  Plus, I don't need to create a new class for every rule as the logic is all contained within the Func.  Also, I can transfer these rules to the UI, drive some control behaviors following them and provide clean feedback to users : All this logic is within my business entity!

Works fine, but I think I'll have my ExecutionRule implement the IBusinessRule and let the BusinessRuleManager handles my per-type collection instead of trying to manage all this by my own...

RockfordLhotka replied on Monday, December 20, 2010

fwiw, CommonRules does include a Lambda rule that allows you to implement a rule "in line" in the AddBusinessRules method, without the need to create a rule type. You give up a bunch of more advanced features (like state management, etc) by not having an object of your own, but for simple rules it is a decent alternative.

I'm not entirely sure I understand what you are trying to accomplish with CanExecuteMethod though? Are you trying to have methods with essentially no method body, because the method is actually implemented in a rule?

crackity_jones666 replied on Monday, December 20, 2010

First of all :  Thanks for your support!  It's great to be able to talk with you before I get to deep in my implementation.  

I may miss something, but is there a way to link a rule to a method?

CanExecute returns true or false (or throws an exception), but there's no way that we can communicate to a user why certains methods are "uncallable"...  That's the whole purpose of the BrokenRulesCollection and that's what I'm trying to achieve with my ExecutionRules...

So what if MethodB cannot be called if the entity is in an mix of specific state...

As an example

public override bool CanExecuteMethod(string methodName)
if (methodName == "MethodB") return this.StateA == State.SpecificState && this.StateB == State.OtherSpecificState


then in an application, I want to link a button with the MethodB and I want it to be disabled if I cannot execute the Method.

As you know, in a silverlight application, I cannot bind the IsEnabled attribute of a button to multiples attributes nor to the CanExecuteMethod("MethodB").  So we initially implement an extra boolean attribute CanExecuteMethodB.  This property can be in the model, or in the view model.

To be able to notify the UI when CanExecuteMethodB changes (raise INotifyPropertyChange), we must listen modifications to the model properties...

protected override void OnPropertyChanged(string propertyName)


if (propertyName == "StateA" || propertyName == "StateB") CanExecuteB = this.StateA == State.SpecificState && this.StateB == State.OtherSpecificState

And then you start listening to all kind of methods (OnPropertyChanged, On ChildChanged, etc...) and you always need to keep in mind what are the actuals attributes than can change the Can attribute.  Maybe we didn't handle this correctly...  I don't like to put logic in multiple methods to have something working...

So what I want is, in a new AddExecutionRules method (Same kind of thing than AddBusinessRules) :  

ExecutionCollection.Add(new MethodExecutionRules("MethodB") 
{
new ExecutionRule<MyEntity>(o => o.StatusA == State.SpecificState, "StatusA"),
                  new ExecutionRule<MyEntity>(o => o.StatusB== State.OtherSpecificState, "StatusB")
          }

CanExecuteMethod can then call the ExecutionCollection, as well as the ViewModelB. Also, I can add Feedback information in the declaration of my ExecutionRule to provide feedback to the users...

Am I missing something?  Is there a better way to handle this nicely?

Thank you so much for your time!

RockfordLhotka replied on Monday, December 20, 2010

In CSLA 4 authorization rules are full-blown objects - which means they can take into account the state of the object or other ambient values (like the user's identity, roles, claims, etc).

CanExecuteMethod really is just a fancy way of running whatever authorization rule you've attached to the method, so you surely should be able to return true/false based on the state of your object.

You are right that data binding (in any UI technology) doesn't work against methods like CanExecuteMethod. That's true of CanReadProperty and CanWriteProperty as well, which is why the PropertyInfo and PropertyStatus controls exist in Csla.Xaml. Those controls elevate the metastate about a property into bindable properties for use in a XAML UI.

There are no "MethodInfo" or "MethodStatus" controls, but I'm not sure that's really required in most (any?) cases. For my part I've taken to always using the MVVM design pattern, so I always have a viewmodel between the view (XAML) and model (business object). It is pretty trivial for a viewmodel to expose a Boolean property indicating whether the method is available or not, and to raise PropertyChanged when that property changes. For that matter, I'd expose a method (command/verb) on the viewmodel for the UI to invoke using TriggerAction or commanding or something - and that viewmodel command would be what actually invokes the method on the model object.

Keep UI concerns in the presentation layer (view and viewmodel) and keep business logic (like authorization rules) in the model.

crackity_jones666 replied on Tuesday, December 21, 2010

Thanks for your reply Rocky!  Turns out this discussion is not a technical one anymore! 

I agree that presentation logic and business logic should remain totally independant.  I'm also using MVVM with command patterns...  My concern is that, using a boolean attribute on the ViewModel, we need listen to Property Changed events on the whole set of attributes that composes it. (If the attribute is CanDo get { AttributeA == AtributeB + AttributeC;}, you need to listen the property changed events on AttributeA, AttributeB and Attribute C) because I don't want to always raise NotifyPropertyChanged("CanDo") on every model property changed.  Finally, for my purpose, a boolean attribute is not enough to provide clear feedback to the user explaining why this control is not enabled.

So, this logic "AttributeA == AtributeB + AttributeC" is in the CanExecuteMethod of the business object and the same logic must be implicitely known in the ViewModel.  So if I change the logic in the CanExecuteMethod, I need to get to the ViewModel and apply the corresponding changes to the PropertyChanged events. 

IMHO, the BrokenRulesCollection is a UI Concern but it stays in the Business layer to be able to provide feedback to users following BusinessRules, and that's exactly what I would like to have for my ExecutionRules...  The implementation of an ExecutionRules collection should allow business / view-model base classes to listen to appropriate property changed events based on the properties handled in the collection.  All I need to do in my implementation is to register those Execution rules et voilà!  Is this an overkill?

Once again, thanks for your time and congrats for this great framework!

 

Copyright (c) Marimer LLC