CSLA.NET 3.6: ByPassPropertyChecks (suggestion)

CSLA.NET 3.6: ByPassPropertyChecks (suggestion)

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


Patrick posted on Saturday, August 09, 2008

Hi,

here a suggestion which might be of benefit for CSLA.NET 3.6.

Currently CSLA.NET 3.5 implements properties in this way:

  private static PropertyInfo<string> NameProperty = RegisterProperty(new PropertyInfo<string>("Name"));
    public string Name
    {
      get { return GetProperty<string>(NameProperty); }
      set { SetProperty<string>(NameProperty, value); }
    }

When I need to get or set the properties from within the business object and like to bypass security checks for performance and other reasons I need to call one of these methods:
  LoadProperty<string>(NameProperty, data.Name);
  ReadProperty<string>(NameProperty),

This is fine especially when the code is code generated. When it's done by hand it's sometimes rather a lot of code to write....
      LoadProperty<string>(NameProperty, "TestName");
vs
     Name = "TestName";

So I was wondering if it would be a good idea to implement in business base:
protected bool _byPassPropertyChecks {get;set;}

When _byPassPropertyChecks is set to true (default false)
* GetProperty<string>(NameProperty) would just call ReadProperty<string>(NameProperty) internally.
* SetProperty..... would just call LoadProperty...... internally.

Considering that business objects are not thread safe anyway there doesn't seem to be much danger and this code to load a project in the ProjectTracker:
        // get project data
        var data = (from p in ctx.DataContext.Projects
                    where p.Id == criteria.Value
                    select p).Single();
        LoadProperty<Guid>(IdProperty, data.Id);
        LoadProperty<string>(NameProperty, data.Name);
        LoadProperty<SmartDate, System.DateTime?>(StartedProperty, data.Started);
        LoadProperty<SmartDate, System.DateTime?>(EndedProperty, data.Ended);
        LoadProperty<string>(DescriptionProperty, data.Description);

Could become:
        // get project data
        var data = (from p in ctx.DataContext.Projects
                    where p.Id == criteria.Value
                    select p).Single();
        byPassPropertyChecks =true;     
        Id = data.Id;
        Name = data.Name;
        Started = data.Started;
        Ended = data.Ended;
        Description = data.Description;
        byPassPropertyChecks =false;

Which is easier to read, quicker to write, and simpler to maintain Smile [:)]

Thanks for considering it,
Patrick

RockfordLhotka replied on Sunday, August 10, 2008

I'll be interested to hear what others think of this idea.

My first reaction is that this is a really good idea.

Here's a broader (and maybe more dangerous) alternative that also seems interesting:

using (new DirectAccess(_project))
{
  _project.Id = dto.Id;
  _project.Name = dto.Name;
  _project.Started = dto.Started;
  // ...
}

The using block seems cleaner than setting the property manually.

The drawback to this approach is (at least as I'm showing it) that external code could use it to cheat, and that could be bad.

But it could be protected only like this:

using (this.BypassPropertyChecks)
{
  Id = dto.Id;
  Name = dto.Name;
  Started = dto.Started;
  // ...
}

Same idea, but using a protected BypassPropertyChecks property so it is only available inside the object.

Patrick replied on Sunday, August 10, 2008

RockfordLhotka:
My first reaction is that this is a really good idea.

Thanks for being so open to suggestions with CSLA.NET Smile [:)]

RockfordLhotka:
The using block seems cleaner than setting the property manually.

Yes it is a lot cleaner and also makes sure that the object is never left in "Bypass" mode should an exception occur during set or get of the property.

RockfordLhotka:
The drawback to this approach is (at least as I'm showing it) that external code could use it to cheat, and that could be bad.

Hm if "DirectAccess" was internal instead of public the harm might be limited... In the case below the Id still couldn't be set from the outside.

  private static PropertyInfo<Int32> IdProperty = RegisterProperty(new PropertyInfo<Int32>("Id"));
    public string Id
    {
      get { return GetProperty<string>(IdProperty); }
      private set { SetProperty<string>(IdProperty, value); }
    }

One benefit would be that it would make it possible to fill a business object from the outside during fetch scenarios. For example LLBLGen supports projection of an open DataReader onto custom business classes which might bean easy way to fill the business objects. The danger seems to be limited as IsValid would still report correctly on the state of the object.

But filling it form the inside works fine too so I'm not sure how much benefit it would bring overall.

Thanks,
Patrick

stefan replied on Monday, August 11, 2008

You probably meant 'protected' instead of 'internal'...

Annesh replied on Monday, August 11, 2008

I like the idea of the 'using' clause, it prevents the developer from forgetting to set the ByPassPropertyChecks to false at the end. Just another simple idea could be to use protected operator overloads methods in the base classes perhaps (.=) or (<-), in which then the usage of this could be Id .= dto.Id.

Fintanv replied on Monday, August 11, 2008

My vote is for the "using" syntax.  It is clean and provides nicely structured, easy to read, code.

-- Fintan

rasupit replied on Monday, August 11, 2008

I like the idea of using "using block".  The second signature looks very clean, however this make the property must return IDisposable object instead of boolean value.

Other option is to call a method to create new "token" object that implement IDisposable similar to ASP.NET MVC's Form helper.

Here's the sample that might work:

    public class MyBusinessObject : Csla.BusinessBase<MyBusinessObject>
    {
        public void Fetch()
        {
            using (GetByPassPropertyToken())
            {
                System.Threading.Thread.Sleep(2000);
            }
        }
        private bool ByPassPropertyCheck = false;

        private IDisposable GetByPassPropertyToken()
        {
            return new ByPassToken(this);
        }
        private class ByPassToken : IDisposable
        {
            private MyBusinessObject B;
            public ByPassToken(MyBusinessObject b)
            {
                B = b;
                B.ByPassPropertyCheck = true;
                Console.WriteLine("Property Check By Passed..");
            }

            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);

            }
            public void Dispose(bool dispose)
            {
                B.ByPassPropertyCheck = false;
                Console.WriteLine("Property Check Back On..");
            }
        }
Note: this would be the same implementation as the first option except the class would be local to BusinessBase.
Ricky.

RockfordLhotka replied on Monday, August 11, 2008

Thanks Ricky – my idea was that the property would return an IDisposable token object – much the way the WPF data provider infrastructure works, and pretty much exactly what you have in your example.

 

Rocky

rasupit replied on Monday, August 11, 2008

I see.. that would work as well.
Ricky

Patrick replied on Monday, September 08, 2008

Hi,

is there any plan to implement this in CSLA.NET 3.6?

Thanks,

Patrick


Patrick replied on Wednesday, September 24, 2008

It seems like this would also help with the DataMapper as mapping data from one object to a business object that is in ByPass mode would allow the DataMapper to also bypass the security checks which would give a performance benefit....
During an internal mapping operation security isn't needed in most case anyway..

Thanks,
Patrick

Patrick replied on Wednesday, October 22, 2008

Hi,

I saw you implemented it in cslalight in the trunk in revision 3190:
http://www.lhotka.net/cslacvs/viewvc.cgi?view=rev&revision=3190

Implement feature: "Implement scheme by which GetProperty/SetProperty can act like ReadProperty/LoadProperty, bypassing authorization and property changed events"  Implement this in BusinessBase and ObjectFactory.
bugid: 70

are there any plans to port it to CSLA.NET 3.6 for windows?

Thanks,
Patrick

RockfordLhotka replied on Wednesday, October 22, 2008

This is in the Windows version too. You can see the file revisions if you click the “svn revisions” link from the bugtracker summary page:

http://www.lhotka.net/cslabugs/edit_bug.aspx?id=70

 

Rocky

Patrick replied on Tuesday, October 28, 2008

RockfordLhotka:

This is in the Windows version too. You can see the file revisions if you click the “svn revisions” link from the bugtracker summary page:

http://www.lhotka.net/cslabugs/edit_bug.aspx?id=70

Hi Rocky,

thanks for your answer. I can see that it's in the windows version but it seems to be missing from 3.6 Beta 2 http://www.lhotka.net/cslacvs/viewvc.cgi/tags/V3/V3-6-0-b2/cslacs/Csla/BusinessBase.cs?view=markup

Thanks,

Patrick

FrankM replied on Tuesday, October 28, 2008

It's in cslacs-3.6.0-081021.zip.

Jack replied on Tuesday, December 02, 2008

This feature only works one level deep right?  I have an object property that returns one of three different ManagedProperties depending on the valueTypeCode stored in a 4th Property.

in pseudo code to make readalbe

Object DataValue =
 Switch(Field.FieldTypeValue)
  case "Number" : return DataProperty.ValueNumber;
  case "Date"   : return DataProperty.ValueDate;
  case "String" : return DataProperty.ValueText;


If I use the ReadProperty then this starts to look like

Object DataValue =
 Switch(ReadProperty<xxx>(Field).ReadProperty<yyy>(FieldTypeValue))
  case "Number" : return ReadProperty(DataProperty).ReadProperty(ValueNumber);

  
etc.

The code looks horrible and is hard to read.

Is there a syntax that will basically use the ByPassPropertyCheck on nested managed properties?

Thanks

jack

 

RockfordLhotka replied on Tuesday, December 02, 2008

How can you even do that? ReadProperty() is a protected member, so you can’t write code in one object to call it in another object – even a child object.

 

Rocky

 

Jack replied on Tuesday, December 02, 2008

That is the problem... I can't :-). 

I'm looking for help/direction in how to handle this.  I'm starting to think I have to go back to the child and change all my codeGen Public abc properties to internal property and ReadProperty vs. GetProperty As its only used by the Parent.

Am I making sense or babbling uselessly?

thx

jack

RockfordLhotka replied on Tuesday, December 02, 2008

In general, one object shouldn’t be mucking around with the fields of another object. That breaks encapsulation and is a major anti-pattern for OO programming.

 

Instead, one object should ask other objects to do things, or ask other objects questions to get data.

 

If this child property is only used by the parent, then it should probably be internal/Friend in scope, and can just use ReadProperty() so you never worry about authorization checks. Though why it would ever have an authz rule if it is only for internal use I’m not sure…

 

Rocky

Jack replied on Tuesday, December 02, 2008

The child property is only used by the parent and creating an internal version is what I am doing.  I guess maybe I am getting too excited about the overhead of the Read vs. Get with no authorization checks.  There is a lot of extra things going on but all the checks will process nothing.

 

So bottom-line is there any real overhead if there are no rules?  I have to do a bunch of these property checks each time the user tabs through a field so limiting the overhead is very important to me.

 

Thx

 

jack

 

From: Rockford Lhotka [mailto:cslanet@lhotka.net]
Sent: December-02-08 4:38 PM
To: jaddington@shaw.ca
Subject: RE: [CSLA .NET] RE: CSLA.NET 3.6: ByPassPropertyChecks

 

In general, one object shouldn’t be mucking around with the fields of another object. That breaks encapsulation and is a major anti-pattern for OO programming.

 

Instead, one object should ask other objects to do things, or ask other objects questions to get data.

 

If this child property is only used by the parent, then it should probably be internal/Friend in scope, and can just use ReadProperty() so you never worry about authorization checks. Though why it would ever have an authz rule if it is only for internal use I’m not sure…

 

Rocky



Jack replied on Tuesday, December 02, 2008

Actually I guess I can improve on my design.  I don't need to the switch/case in the parent - it should do it in the child which eliminates one level and makes more sense with the ReadProperty in the child.

jack

FrankM replied on Tuesday, October 28, 2008

There is another BusinessBase.cs under Core folder. The one Patrick provided is under Csla root defining BusinessBase, which is inherited from Csla.Core.BusinessBase.

The BypassPropertyChecksObject is created in Csla.Core.BusinessBase.

Patrick replied on Tuesday, October 28, 2008

FrankM:
There is another BusinessBase.cs under Core folder. The one Patrick provided is under Csla root defining BusinessBase, which is inherited from Csla.Core.BusinessBase.

The BypassPropertyChecksObject is created in Csla.Core.BusinessBase.

You are right it's in Core.BusinessBase...of the download.
It's still not in the Beta 2 tag for CSLA 3.6 though:
http://www.lhotka.net/cslacvs/viewvc.cgi/tags/V3/V3-6-0-b2/cslacs/Csla/Core/BusinessBase.cs?view=markup

I guess I shouldn't use the repository to get my version but rather download them :)

Thanks,
Patrick

RockfordLhotka replied on Tuesday, October 28, 2008

I don't know why the tag is wrong...

If you want the current stuff though, use /trunk - it includes a couple bug fixes and lots of new comments (that's my primary focus now, bug fixing and commenting).

Copyright (c) Marimer LLC