LoadProperty --> BypassPropertyChecks() --> etc..

LoadProperty --> BypassPropertyChecks() --> etc..

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


rfcdejong posted on Friday, December 05, 2008

Im a bit confused in what is best to use while constructing an business object.
With an BusinessObject derived from BusinessBase the following seems the best way, with the new BypassPropertyChecks()

public class CampagneFactory : ObjectFactory
{
      
public Dias.Business.CampagneBO.Campagne Fetch(CriteriaBase criteria)
      {
            Dias.Business.CampagneBO.
Campagne result = (Dias.Business.CampagneBO.Campagne)Activator.CreateInstance(typeof(Dias.Business.CampagneBO.Campagne), true);

            
using (this.BypassPropertyChecks(result))
            {
                  
result.Campagnenummer = 1;
                  result.Omschrijving =
"foo";
                  result.CampagneStatus =
"bar";
            }            
            
return result;
            }
      }
}

But when it comes to Info objects there is ofcourse not always a setter needed.
I can't find a good way using the object factory to LoadProperty's

Using the Datamapper with a Datamap definition feels like an ugly way of doing it.

 

RockfordLhotka replied on Friday, December 05, 2008

I totally agree. I am open to suggestions on ways to make this better.

There is a non-generic LoadProperty() method internal to CSLA - it is for use by DataMapper. I could expose a protected non-generic LoadProperty() from the ObjectFactory base class. If your business object is using managed backing fields, this would solve the problem. However, the non-generic LoadProperty() method does type coercion because it doesn't know that the input value matches the field type - and that has a perf cost.

The thing is, if you are using private backing fields, you'd still be on your own...

Right now though, that is my only obvious answer. As I say, I'm open to suggestions.

rfcdejong replied on Monday, December 08, 2008

hmm internal setters or internal constructor
not such nice as well, but fast..
using InternalsVisibleTo("factoryassembly")

Or "set once" setters.. once an property is set it will throw an exception

PS: I don't even know if using the Activator.Create is smart to use :)

RockfordLhotka replied on Monday, December 08, 2008

The thing to remember is that I created the ObjectFactory feature primarily to support possible future features of ADO.NET Entity Framework. I am reluctant to do any more than I have to in order to make it work now, because I can’t predict exactly what EF will require when/if those features exist.

 

In other words, if I do too much now, I may end up undoing it (and thus breaking you) later when I finish the support for EF. Supporting EF is the primary purpose, and I’ll implement breaking changes within the ObjectFactory space to make it work when the time comes.

 

Rocky

rfcdejong replied on Monday, December 08, 2008

I though the ObjectFactory is implimented for:

1) To let the businessobject be less heavy when working for example: with Silverlight.
2) For people who don't like DataAccess in the businessobjects
3) To allow unit testing a bit more, but not in a TDD fashion way thru ;)

Or am i wrong?

Guess í'll just make a internal constructor for the info objects.
And then "assembly: InternalsVisibleTo()"

RockfordLhotka replied on Monday, December 08, 2008

You have a list of great side-effects :)

 

My primary purpose in creating ObjectFactory is to prepare for a future where EF can be used to directly load CSLA objects. Hopefully that future happens.

 

Secondary benefits include the items you list.

 

But I have no way of predicting how people are going to want to load their objects with data. No matter what you do, you are breaking encapsulation by directly setting field values from a factory object – and while I agree that this is necessary, it is also a cardinal sin in OOP

 

Some people may choose to hand a DTO to their objects rather than setting fields from the factory. This avoids breaking encapsulation, but is a bit more complex.

 

I don’t yet know for sure what EF will support, and so can’t entirely predict what I’ll need to do to make EF work.

 

So there are at least 3 object loading models I know of today:

 

1.       Load fields directly from factory

2.       Pass DTO/entity to business object so it can load its fields

3.       Whatever EF needs

 

My guess is that there are others. Well, I know there are others – they’ve been discussed in other threads (custom interfaces, friend assemblies, etc).

 

If I make ObjectFactory support all these options the result, I suspect, will be an unusable mess. AND I run the risk of breaking a lot of people when I make EF work when EF matures.

 

At the moment I’ve opted for caution. I’m doing as little as necessary to enable the scenario, so people (like you) can explore the various options to see what works best/worst/etc.

 

If it turns out that some scenario is really compelling, I may support that scenario directly – while still trying to not block all the other options.

 

Rocky

RockfordLhotka replied on Monday, December 08, 2008

To be clear, I don’t disagree with the LoadProperty() idea necessarily – I’m just trying to balance a number of competing concerns.

 

I have added this to the wish list (http://www.lhotka.net/cslabugs/edit_bug.aspx?id=258).

 

Rocky

RockfordLhotka replied on Friday, January 23, 2009

In the next drop of 3.6.1 there'll be a LoadProperty<T>(object, PropertyInfo<T>, value) method in the ObjectFactory base class.

While the syntax is obviously not exactly like what you'd find in a DataPortal_XYZ method, it is quite comparable, and works like the MarkOld() and other methods exposed by ObjectFactory.

rfcdejong replied on Saturday, January 24, 2009

Thanks, i'll update the source when i'm back at work. We didn't write too many objectfactory's yet.

I wonder if they work with readonlybase objects as well. This might remove the friendassembly requirement and the need of using internal setters c.q. internal constructers.

RockfordLhotka replied on Saturday, January 24, 2009

It should work with ROB as well as BB, though I didn't test that. But both
ROB and BB implement the interface necessary for the function to work.

Rocky


-----Original Message-----
From: rfcdejong [mailto:cslanet@lhotka.net]
Sent: Saturday, January 24, 2009 7:08 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: LoadProperty --> BypassPropertyChecks() -->
etc..

Thanks, i'll update the source when i'm back at work. We didn't write too
many objectfactory's yet.

I wonder if they work with readonlybase objects as well. This might remove
the friendassembly requirement and the need of using internal setters c.q.
internal constructers.

bniemyjski replied on Thursday, January 07, 2010

Hello,

I am about 95% done implementing object factory support in the new CodeSmith templates. I came across a shocking issue and that is you can't update a read only property via the Object Factory unless you add an internal setter and set the InternalsVisibleTo Assebmly attribute. I find that I am in a bit of a dilemma because I don't want to make the setter internal and I 100% don't want to expose other assembly's to my BO's via the InternalsVisibleTo attribute.

Is there a work around for this. Is there any method in the CSLA framework that I could set this property via the RegisterProperty / PropertyInfo.

Thanks
-Blake Niemyjski

RockfordLhotka replied on Thursday, January 07, 2010

The ObjectFactory base class has a LoadProperty() method you can use to load
any managed property without calling the setter at all.

jamie.clayton replied on Thursday, January 07, 2010

Blake,

I'm also concerned about this code exposure. It looks like the MSDN documentation for the assembly attribute allows you to specify public keys of assemblies that would be "approved".
http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.internalsvisibletoattribute.aspx.

Apparently you can also chain multiple different signed assemblies into this approval configuration via http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

This creates a dilema for code generation as you will not know about strong name keys during generation and it might create and strong naming key management issue limit the exposure of the internals to other parts of your application.

I wonder if you should just add a TODO: Monika to the generated code with a note about populating assemblies and public keys and the implication of the application SN signing issues that this will generate.

Rockies examples seems to gloss over this issue. I wonder how many people must be actually using this in production code. I would think that readonly SQL Server identity and timestamp fields would be fairly common practice these days.

I wondered about FXcops opinion. The new code analysis feature in VS2010 (Beta2) produced no warnings about using Assembly: InternalsVisibleTo("MyCslaDal") attribute based on a simple two tier test.

Most of the online (google) discussion seems to indicate this was Unit testing feature added to the .net framework, rather than general software assemblies.

jamie.clayton replied on Thursday, January 07, 2010

Or you could use the loadproperty feature that Rocky recomended...DOH!

bniemyjski replied on Friday, January 08, 2010

My PropertyInfo is a private member and not exposed in the ObjectFactory.

private static readonly PropertyInfo _cartIdProperty = RegisterProperty(p => p.CartId);
[System.ComponentModel.DataObjectField(true, true)]
public int CartId
{
get { return GetProperty(_cartIdProperty); }
}

RockfordLhotka replied on Friday, January 08, 2010

LoadProperty() still works in this case. As long as it is a managed backing field, LoadProperty() will work.

bniemyjski replied on Friday, January 08, 2010

The scope is private thus I can't use it in LoadProperty(). This is something I really wouldn't want to make public either.

private static readonly PropertyInfo _cartIdProperty = RegisterProperty(p => p.CartId);
[System.ComponentModel.DataObjectField(true, true)]
public int CartId
{
get { return GetProperty(_cartIdProperty); }
}

RockfordLhotka replied on Friday, January 08, 2010

That's what I'm saying though - I've switched to making all the
PropertyInfo fields public as a general rule. They contain metadata that
is valuable not only to the object, but also to the UI and DAL.

And frankly making them public better matches the
DependencyObject/DependencyProperty usage, which is the basis for my design
anyway.

rxelizondo replied on Friday, January 08, 2010

RockfordLhotka:

I've switched to making all the PropertyInfo fields public as a general rule. They contain metadata that is valuable not only to the object, but also to the UI and DAL.


Its kind of scary to expose a class such as PropertyInfo to the public when you are making a property such as "Index" also available to the public.

Its could also be kind of confusing to a user to see methods like "NewFieldData" exposed to them since methods like that are of no use to them (even if ti takes them to do an explicit cast to IPropertyInfo to see them)

Could we at the very least make the "Index" property and explicit declaration such as:

int Core.IPropertyInfo.Index
{
get
{
return _index;
}
set
{
_index = value;
}
}

bniemyjski replied on Friday, January 08, 2010

Hello,

I'm still searching for a better approach, I'm not happy with exposing information like this. I can see its uses in this one case but the more information I can keep hidden and out of scope the better.

@rxelizondo, that could be an interesting idea.

Thanks
-Blake Niemyjski

RockfordLhotka replied on Friday, January 08, 2010

rxelizondo:
Its kind of scary to expose a class such as PropertyInfo to the public when you are making a property such as "Index" also available to the public.

That is a good point and is a change that should be made.

bniemyjski replied on Monday, January 11, 2010

Hello,

So I looked into this some more and it looks like the only approach is to make an internal setter :\.

Thanks
-Blake Niemyjski

rfcdejong replied on Monday, December 08, 2008

Btw, exposing the protected non-generic LoadProperty to the ObjectFactory base class sounds fine by me. But must it be the non-generic LoadProperty?

I would like to see that both the normal and the info objects can be constructed the same way.

Copyright (c) Marimer LLC