BusinessBase.PropertyHasChanged calling ValidationRules.CheckRules in Version 2.1.1BusinessBase.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.
jimboJimbo 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