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
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 NiemyjskiRockfordLhotka 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 NiemyjskiRockfordLhotka 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 Niemyjskirfcdejong 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