Custom Properties and _bypassPropertyChecks

Custom Properties and _bypassPropertyChecks

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


xal posted on Thursday, December 01, 2011

There is a problem when implementing a custom property, that doesn't really have it's own data, but instead consumes other properties for managing it's state. Example: 2 standard managed properties, StartValue, EndValue. 1 "custom" property  that feeds on these two: DifferenceValue


  Public Shared ReadOnly DifferenceValueProperty As PropertyInfo(Of Integer) = RegisterProperty(Of Integer)(Function(o) o.DifferenceValue, "Difference", RelationshipTypes.PrivateField)
  Public Property DifferenceValue As Integer
    Get
      CanReadProperty(DifferenceValueProperty, True)
      Return ReadProperty(EndValueProperty) - ReadProperty(StartValueProperty)
    End Get
    Set(value As Integer)
      CanWriteProperty(DifferenceValueProperty, True)
      LoadProperty(EndValueProperty, ReadProperty(StartValueProperty) + value)
      PropertyHasChanged(DifferenceValueProperty)
      PropertyHasChanged(EndValueProperty)
    End Set
  End Property

There's no way to determine if there's currently a Bypass in place, so you can't prevent the calls for canread/write from throwing exceptions. This could be solved by either exposing the current value of _bypassPropertyChecks through a protected readonly property or checking it's value from within CanReadProperty / CanWriteProperty. The former seems better because you may still want to check during a bypass if the current user could write to a property.

As a side note, it seems appropriate to use "RelationshipTypes.PrivateField" in this scenario, but there really is no private field.

 

Andrés

JonnyBee replied on Thursday, December 01, 2011

To possibilites from me:

A: Change to be a property with a backing fiied and have rule that "calculates" the value based on the other two/three input values. InputProperties is automatically depencies in CSLA 4.2 so the value will be recalculated and OnPropertyChanged raisen when any of the input properties is changed.

B. In CSLA 4.2 we support nested BypassPropertyChecks (using reference counting just like <database>Context).

I'd recommend option A- to just keep it as a simple property (maybe add an authorization rule to never allow edit of the field) and use a BusinessRule.

 

 

RockfordLhotka replied on Thursday, December 01, 2011

Jonny's option A is preferred. The idea is that all business logic should be encapsulated in rule types.

This means a calculated value should be calculated by a rule, not in a getter. And that means that the calculated property should be a real property, and its value should be set by the rule.

xal replied on Thursday, December 01, 2011

Hi Jonny and Rocky, thanks for your replies.

I see how in theory option A is great, but in practice it's impractical and it implies performance hits across all tiers. I have scenarios with 10 or more calculated properties, most of them editable and affecting other properties values, some of them are strings that are returned based on a resource value and formatted with values from other properties as well, the resource to be used can vary depending on the value of yet another property.

In a collection with many objects, storing all these extra values has a huge impact:

-Loading the collection will take longer.

-Serializing the collection and moving it through the wire means more bandwidth and even more time.

-Client side and server side memory and cpu penalties.

There are cases when such collections are retrieved and those properties might not even be consumed. so you'd be getting all that extra overhead for nothing.

I agree that this is in a sense a business rule. But this can also be looked at as behavior, something that could be done in a method to affect other properties. And it actually is implemented through 2 methods, the getter and the setter of a property, the property wrap just gives you the added bonus of data binding. If I were creating a method called "void AdjustEndValueBy(int difference)" I wouldn't want it's implementation inside a business rule and I believe this is the same scenario.

Either way, I don't see why this should be not allowed. And the fact remains that if you do implement a custom property there's no way for you to know if the BO is currently bypassing checks.

The GetProperty method does this "if(_bypassPropertyChecks || CanWriteProperty(..))". You can't replicate that in the derived class because there is no protected property that exposes the current status of _bypassPropertyChecks. I knew about the nesting of BypassPropertyChecks but it is unrelated to this.

I think we need a protected bool IsBypassingPropertyChecks{ get { return _bypassPropertyChecks;}}

 

Cheers

Andrés

JonnyBee replied on Saturday, December 03, 2011

One more option is to put the "calculation" code into a PropertyHasChanged override.

When BypassPropertyChecks is true then no PropertyHasChanged is called.
And you can also raise new OnPropertyChanged events for calulated properties.

I always prefer to keep the property declaration code as straight and simple as possible.

xal replied on Sunday, December 04, 2011

We will always agree on wanting the code to be simple and elegant. But the fact remains that this will add overhead and memory consumption. It's not a big problem in a single root object, but in large collections calculated properties are the way to go. Creating storage space for a calculated value will also create redundant data and increases the chances for having bugs.

Here's a really really common scenario: you have a lookup. The key type is byte, you have around 20 possible values and the descriptions can be rather long. I'm loading the collection with 500 rows. Do I want to load 500 bytes or 20kb? What if you have more properties like that? The best answer is to use dictionaries in the properties to reduce load, memory and to have good response times when reading the properties.

All that is required to enable this scenario is to expose the current status of _bypassPropertyChecks through a property. It's just another status indicator, such as isvalid, isdirty and isbusy, although this one shouldn't be public.

tmg4340 replied on Monday, December 05, 2011

I realize this is a little off the mark of where this post has gone, but I'm still confused about something:

Why would you want your calculated property to have different security constraints than its dependent properties?  Your main concern seems to be that the ability to detect whether you're in a bypass-security block is missing.  Setting aside whether that's a good thing to know or not, I'm wondering why it's important in this situation.  Surely a user's ability to read/write a property whose value is dependent on other properties would be the same as those dependent properties, thus obviating the need to know whether a bypass block is active.  So I must be missing something...

As to your performance questions, I will say that business rules are by type, not by instance, and thus are loaded only once.  Yes, that is a bit more overhead than a straight calculated property, but it isn't that much.  I'm also not following your example too well; if you have a lookup, wouldn't you load the lookup values in a ROL (or an NVL) only once, and do the translation in your UI?  There doesn't seem to be any overhead there - at least not any you can realistically get rid of.  If you're talking about a read-only scenario, then I'd just load the descriptions directly - also a situation where I don't see much overhead that can be removed.  So again, I must be missing something.

- Scott

xal replied on Monday, December 05, 2011

Well, the calculated property could definitely have its own security constraints. Imagine you have a class that has a base value, let's call it weight, 3 different price categories, one for retailers, one for class "a" customers and one for regular customers, one general cost per weight multiplier (this is an extremely over simplified version of a company's requirement).
Weight and cost multiplier properties are regular properties. The prices are all calculated. A user may be able to see only one category of those prices. The independent multipliers for each category come from settings outside this class, not from properties in the class itself. So there you have a scenario where the base properties don't necessarily have a say on the access to a calculated property.
Now, a user could have access to viewing and editing prices to just one class, or 2 classes or all three. Changing a price would affect the base multiplier and if you have access to more than one pricing class, you could see how it affected the other classes as well. This would then go to a staging database where all the data collected and prices estimated by the end users would be analyzed to define the final prices to all categories. In this stage a user would have access to the same business object but instead of affecting the price multipliers per item, it would alter the category multiplier, affecting hundreds of objects at the same time.


Having all this in rules would mean long execution times, higher memory usage and redundancy. It would also affect serialization and transfer over the wire as well. Not because of the rule, I know they are only loaded once by type, but because of the properties themselves. Why even recalculate it if the user will never be able to see it? So that's why you use calculated properties. Some calculations may be more complex, taking longer time, like getting coordinates for an address or interacting with the file system, a web service, loading other child objects on demand. There are heaps of possibilities. For some of them I wouldn't consider using properties, for some of them I would.
The issue here is having the choice of using a calculated property or a storing a value. And right now if you want to create a calculated property you would have to choose not to enforce security on that property or maintain a modified copy of csla to enable that. It's not a huge deal for me, but I see it's something that other people will want to do.


On the other subject yes, sometimes you can take care of the lookup in the UI, but if the collections are used in different scenarios you’d have to replicate that logic over and over. What if the lookup is not just a regular “dropdown selection” situation? Sometimes you have a calculation that depends on a lookup value. Do you want to replicate those calculations in the UI? Generally, the answer is no. As Rocky always says, UI code is the most expensive, and I agree 100%.
If you have an application that will be used by 10 users in a local network and will only be working with a simple root objects, then of course you wouldn't care and create an extra field, but if you need to create something for a large user base, that moves relatively large amounts of data then you need to think about these issues. If the difference becomes 20k to 200k in a dataportal operation then you have a problem.


I’m currently migrating a very large application from windows forms to MVC.  It was built with csla 2.1 and I’m porting everything to the latest version because it’s better suited for that purpose. The migration will take a very long time and in the meantime the windows forms client needs to be maintained, so the window forms client will have to work with the same library (and yes, I’m using businessbindinglistbase).
There are many places where this application uses calculated properties. Sometimes calculated properties depend on other calculated properties and sometimes they are chained many times. Not only there is nothing wrong with this, I believe it is a good practice. I also believe that performing those calculations in rules and storing the results will make the code harder to understand and maintain, and will open the door for more bugs.

 

Anyway, I hope that clarifies it.

 

Cheers!

Copyright (c) Marimer LLC