BusinessBase.PropertyHasChanged calling ValidationRules.CheckRules in Version 2.1.1

BusinessBase.PropertyHasChanged calling ValidationRules.CheckRules in Version 2.1.1

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


Jimbo posted on Monday, November 27, 2006

I am having a problem getting the call to ValidationRules.CheckRules in PropertyHasChanged() or PropertyHasChanged(propertyName) to work. - for either Instance rules or Type rules ( inc Common Rules)
The only way i can get a result is to call ValidationRules.CheckRules() or ValidationRules.CheckRules(propertyName) directly in my property setters..

Note I have tried setting NoInlining on/off with no difference.

Any Ideas ?

sam replied on Tuesday, November 28, 2006

Hi,

Please clarify yours problem.

Sam

Jimbo replied on Wednesday, November 29, 2006

Hi Sam

To outline the position a bit :

We have am EditableRoot Business class with regular property setters as in the standard template like:

#Region " Business Methods "

Private mId1 As Integer
Private mId2 As Integer

  Public Property Id1() As Integer
    Get
      CanReadProperty(True)
      Return mId1
    End Get
    Set(ByVal value As Integer)
      CanWriteProperty(True)
      If mId1 <> value Then
        mId1 = value
        PropertyHasChanged("Id")
      End If
    End Set
  End Property

Public Property Id2() As Integer
    Get
      CanReadProperty(True)
      Return mId2
    End Get
    Set(ByVal value As Integer)
      CanWriteProperty(True)
      If mId2 <> value Then
        mId2 = value
        PropertyHasChanged("mId2")
      End If
    End Set
  End Property

'/ other Read/Write properties here

Public ReadOnly Property uid As String
    Get
      Return Right("000000" & mId1,6) & Right("000000" & mId2,6)
    End Get
End Property

  Protected Overrides Function GetIdValue() As Object
    Return uid
  End Function

#End Region

We are using "Windows" authorization.
There are no Auth restrictions on Read/Write/object.
The uid defines a composite primary key.
Both Id1 and Id2 start with an initial value of zero.
The Class is Bound dynamically to the form BindingSource
The form controls are in turn Databound dynamically to the BindingSource - standard stuff

AddBusinessInstanceRules:
 Instance rules have been added for many properties including Id1 and Id2 using Common Rules and custom rule delegate functions.

ValidationRules.CheckRules:
In the Create method we call ValidationRules.CheckRules() directly ( as in the book)
This will also be called in the Save method after rebinding.

In both cases the calls work and the validation rules are invoked correctly.

note: We are not using the csla DataPortal or passing mobile objects.
ie: we are using generic datatables and parameterized ADO.Net data access methods.
The application talks to an existing com+ app server through a tcp remoting Service or IIS/Soap.
.......................................................................................

The Problem:

As you know, calls to BusinessBase.PropertyHasChanged("propertyName") or BusinessBase.PropertyHasChanged() from a property setter will in turn call ValidationRules.CheckRules("properyName") or ValidationRules.CheckRules().

If you step through the code in debug mode it is apparent that the correct rules list is found.
However the rule methods themselves do not get invoked.

Note the invocation of the rule delegates happens fine when ValidationRules.CheckRules("properyName") or ValidationRules.CheckRules() is called directly from  anywhere in the business class, for example, in the property setters just before calling
PropertyHasChanged("propertyName")

With reference to the recent discussion points on Inlining, we have tried setting this attribute option  on the property getters and setters  but with the same result.

Regards
Jimbo



david.wendelken replied on Wednesday, November 29, 2006

Have you tried this in front of each getter and setter?

 

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]

Jimbo replied on Wednesday, November 29, 2006

Thanks but Yes , as i said in my last paragraph, the attribute setting has been tried according to Rocky's posts.
btw it would be better if you can set this as a global compiler directive rather than having to remember to add it in every getter and setter.

jimbo

Jimbo replied on Wednesday, January 03, 2007

Sorry to have to  resurrect this issue guys, but its important.  100000 lines of vb6 - com+ enterprise legacy code migrating  to .net 2 and system.transactions.  The Csla framework has done wonders for removing the  form-in-charge spagetti and smoothly dealing with binding etc,. but this issue with the base classes still prevails.

Brian Criswell replied on Wednesday, January 03, 2007

Could you post your override of the AddRules method for the above object?  Also, it probably is nothing but the PropertyHasChanged call should be for "Id2" not "mId2".

Jimbo replied on Wednesday, January 03, 2007

Thanks Brian,
please treat the example code as pseudo - there are some symantical errors (posted off the top of the head at the time).
The core of the problem however is that the call to PropertyhasChanged() in the property setters does not seem to invoke ValidationRules.CheckRules() as expected. And,  (not illustrated in the original code) it is necessary to add an explicit call to ValidationRules.CheckRules() or ValidationRules.CheckRules("PropertyName") in every property setter to ensure that it happens.

Its been a few weeks since my original post and maybe i need to revisit - but so far as my my co-developers have observed, the problem still exists.




.


RockfordLhotka replied on Wednesday, January 03, 2007

I would recommend setting a breakpoint at the call to PropertyHasChanged() and walking through the code in the debugger to find out why the call isn't working. There aren't conditionals in that method, so CheckRules() must be called - but perhaps there's some other issue that is causing it to not check the rules for your property or something like that.

Also note that if you are using the string literal overload of PropertyHasChanged() like you show in your pseudocode, then you don't need the NoInlining attribute on the property get/set. That attribute is only required if you are NOT specifying the property name explicitly for CanReadProperty(), CanWriteProperty() and PropertyHasChanged().

Finally, remember that the cross-reference process for rules is ultimately string based. So you MUST ensure that the property name used in AddRules() is the same as the one for PropertyHasChanged() - including case - or the ultimate call to CheckRules() will simply not find any rules to process.

mr_lasseter replied on Wednesday, January 03, 2007

  Public Property Id1() As Integer
    Get
      CanReadProperty(True)
      Return mId1
    End Get
    Set(ByVal value As Integer)
      CanWriteProperty(True)
      If mId1 <> value Then
        mId1 = value
        PropertyHasChanged("Id")
      End If
    End Set
  End Property

Public Property Id2() As Integer
    Get
      CanReadProperty(True)
      Return mId2
    End Get
    Set(ByVal value As Integer)
      CanWriteProperty(True)
      If mId2 <> value Then
        mId2 = value
        PropertyHasChanged("mId2")
      End If
    End Set
  End Property

 

Should be PropertyHasChanged("Id1") and PropertyHasChanged("Id2")

Jimbo replied on Thursday, January 04, 2007

Mr Lasseter,
I agree with your observation , the literal stings in the example pseudo code are incorrect . So I should fix this and post REAL code ( tomorrow), so that we dont spend time on side issues.

With respect to Rocky's advice, I believe we have adhered to the correct aspect of property names in the case of string literals. And  in other cases tried the reflection route to no avail.

Calling ValidationRules.CheckRules() or ValidationRules.CheckRules("propertyname") explicitly - ALWAYS works. But not when you walk through PropertyHasChanged() ...  the framework finds the rules collection ok, but then fails to invoke the delegate, be it Type or Instance rules.

One aspect of Rocky's comments may or may not be pertinent::
he mentions the use of CanReadProperty and CanWriteProperty.  In all cases we are assuming the default authorizaton to be TRUE, as custom authorization on individual properties is not implemented.. One would think that the framework is not a user in that sense and these redundant calls should have no affect..








RockfordLhotka replied on Thursday, January 04, 2007

Let me reiterate my suggestion: walk through your code in the debugger to see what is happening.

Only two people before has had this issue, and the problem turned out to be an exception that was thrown in their code.

The first had the exception before PropertyHasChanged() was called. Data binding silently ate that exception and of course PropertyHasChanged() was never called at all.

The second had a bug in their first rule method so it threw an exception, aborting all further rule processing.

Because data binding can hide exceptions, you can only debug this stuff using either the debugger or unit tests (like with nunit) so the properties are set from other code, not through data binding.

Jimbo replied on Wednesday, January 17, 2007

Rocky,
I think this issue is closed.
Thanks for the wise words.  One really has to be diligent with string literals etc.
Interesting that the process was repaired some time before i realized, as I still had redundant  ValidationRules.CheckRules("propertyName") calls in every property. Also there were potential case issues between the use of property names ending in Id vs ID.  I dont know what the real solution was, but I suspect it was the refinement of the construction of the <DataObjectField> uid property for the composite primary key.  In later classes I am dealing successfully with databinding with up to 5 concatinated fields.

jimbo




Copyright (c) Marimer LLC