CSLA .NET 3.5 Beta 1 available

CSLA .NET 3.5 Beta 1 available

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


RockfordLhotka posted on Monday, January 28, 2008

I have made CSLA .NET version 3.5 Beta 1 online for download at www.lhotka.net/cslanet/download.aspx. Both VB and C# versions are available.

Please read the change log to get an idea of all the changes, and check out the various 3.5 related threads here on the forum as well.

At this point version 3.5 is feature complete - I'm not adding anything new.

There are probably some bugs, and any help you can provide in finding them and letting me know about them is VERY appreciated!!

Barring anyone finding some major hole in my implementation, the only changes going forward should be bug fixes and stability and performance enhancments. The public API for mainstream business object creation should be stable going forward. Advanced extensibility APIs may still be subject to change, though I hope not.

(For those working with the 3.5 preview releases, there's one big change you should know about up front. The property declaration syntax now requires you to use a RegisterProperty() method. Check the change log and/or ProjectTracker.Library to see the new syntax. I apologize for making such a change right before beta, but the 30%+ performance increase was too important...)

phucphlq replied on Monday, January 28, 2008

It’s great!

 

Can I build it with .Net 2.0?

 

Thanks

 


From: RockfordLhotka [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 06:46
To: phucphlq@dsp.com.vn
Subject: [CSLA .NET] CSLA .NET 3.5 Beta 1 available

 

I have made CSLA .NET version 3.5 Beta 1 online for download at www.lhotka.net/cslanet/download.aspx. Both VB and C# versions are available.

Please read the change log to get an idea of all the changes, and check out the various 3.5 related threads here on the forum as well.

At this point version 3.5 is feature complete - I'm not adding anything new.

There are probably some bugs, and any help you can provide in finding them and letting me know about them is VERY appreciated!!

Barring anyone finding some major hole in my implementation, the only changes going forward should be bug fixes and stability and performance enhancments. The public API for mainstream business object creation should be stable going forward. Advanced extensibility APIs may still be subject to change, though I hope not.

(For those working with the 3.5 preview releases, there's one big change you should know about up front. The property declaration syntax now requires you to use a RegisterProperty() method. Check the change log and/or ProjectTracker.Library to see the new syntax. I apologize for making such a change right before beta, but the 30%+ performance increase was too important...)



RockfordLhotka replied on Monday, January 28, 2008

CSLA .NET is for .NET 3.5 only. I’m using new language features that are only in the 3.5 C#/VB compilers.

 

CSLA .NET 3.0.x is the .NET 2.0/3.0 version of CSLA and will remain so until it all fades away into the past. I’ll release 3.0.4 (bug fixes) when I release 3.5, and will create other point releases if needed for bug fixing, but the future is .NET 3.5.

 

Rocky

 

 

From: Pham Huu Le Quoc Phuc [mailto:cslanet@lhotka.net]
Sent: Monday, January 28, 2008 7:07 PM
To: rocky@lhotka.net
Subject: RE: [CSLA .NET] CSLA .NET 3.5 Beta 1 available

 

It’s great!

 

Can I build it with .Net 2.0?

 

Thanks

 


From: RockfordLhotka [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 06:46
To: phucphlq@dsp.com.vn
Subject: [CSLA .NET] CSLA .NET 3.5 Beta 1 available

 

I have made CSLA .NET version 3.5 Beta 1 online for download at www.lhotka.net/cslanet/download.aspx. Both VB and C# versions are available.

Please read the change log to get an idea of all the changes, and check out the various 3.5 related threads here on the forum as well.

At this point version 3.5 is feature complete - I'm not adding anything new.

There are probably some bugs, and any help you can provide in finding them and letting me know about them is VERY appreciated!!

Barring anyone finding some major hole in my implementation, the only changes going forward should be bug fixes and stability and performance enhancments. The public API for mainstream business object creation should be stable going forward. Advanced extensibility APIs may still be subject to change, though I hope not.

(For those working with the 3.5 preview releases, there's one big change you should know about up front. The property declaration syntax now requires you to use a RegisterProperty() method. Check the change log and/or ProjectTracker.Library to see the new syntax. I apologize for making such a change right before beta, but the 30%+ performance increase was too important...)

 



skagen00 replied on Tuesday, January 29, 2008

Kind of a big change in there with the RegisterProperty at the last moment!

After having made the changes to my objects, I'm getting an interesting behavior.

For instance, with one property, it'll crash reliably upon trying to load it.

LoadProperty<string>(_sortName, sdr.GetString(_sortName.DataColumnName));

+  $exception {"Property load or set failed for property SortName (Unable to cast object of type 'System.Int32' to type 'System.String'.)"} System.Exception {Csla.PropertyLoadException}

But then, after re-trying the request, it breezes through it and works fine. But then gets caught up with another problem:

DataPortal.Fetch failed (Property load or set failed for property SystemId (Index was outside the bounds of the array.))

Again, re-trying the request I end up skipping through this error as well.

It's possible I may be running into some problems with a concern I had once I saw this change with respect to inheritance and properties that exist in generic abstract classes, but I'll know more once I look into it further. With the preview release, I was working fine with the properties. (We happen to use a derivative of PropertyInfo but it's really nothing).

 


 

 

RockfordLhotka replied on Tuesday, January 29, 2008

I was not keen on making such a big change like that, but the performance benefits are remarkable. There’s a very real cost to using this managed field concept, and performance tuning is important – especially a straight-up 30% improvement!

 

I could see where properties in abstract classes could be problematic. You probably need to register them in the subclass, even though the implementation is in the base class. Interesting problem…

 

Rocky

 

 

From: skagen00 [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 9:48 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: CSLA .NET 3.5 Beta 1 available

 

Kind of a big change in there with the RegisterProperty at the last moment!

After having made the changes to my objects, I'm getting an interesting behavior.

For instance, with one property, it'll crash reliably upon trying to load it.

LoadProperty<string>(_sortName, sdr.GetString(_sortName.DataColumnName));

+  $exception {"Property load or set failed for property SortName (Unable to cast object of type 'System.Int32' to type 'System.String'.)"} System.Exception {Csla.PropertyLoadException}

But then, after re-trying the request, it breezes through it and works fine. But then gets caught up with another problem:

DataPortal.Fetch failed (Property load or set failed for property SystemId (Index was outside the bounds of the array.))

It's possible I may be running into some problems with a concern I had once I saw this change with respect to inheritance and properties that exist in generic abstract classes, but I'll know more once I look into it further. With the preview release, I was working fine with the properties. (We happen to use a derivative of PropertyInfo but it's really nothing).

 


 

 



skagen00 replied on Tuesday, January 29, 2008

Rocky: I could see where properties in abstract classes could be problematic. You probably need to register them in the subclass, even though the implementation is in the base class. Interesting problem…

That seems to me to be a bit of a problem... hopefully there's a way around this.

RockfordLhotka replied on Tuesday, January 29, 2008

I’m open to suggestions J

 

The challenge of course, is that the list of properties for a type is stored in a dictionary keyed by that type. Each PropertyInfo object has an Index property that is set to a specific array location.

 

So actually registering in the subclass won’t necessarily help either, as reuse of a PropertyInfo isn’t possible. If a PropertyInfo was used in 2+ types the Index property would only be valid for one of them and would mess things up in the other(s).

 

There’s no guarantee of the order in which static initialization occurs either. In other words, the base class could be initialized after the subclass, so I can’t necessarily just grab the list of PropertyInfo objects from the base class type, because they might not yet be in the dictionary.

 

Rocky

 

 

From: skagen00 [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 10:21 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: CSLA .NET 3.5 Beta 1 available

 

Rocky: I could see where properties in abstract classes could be problematic. You probably need to register them in the subclass, even though the implementation is in the base class. Interesting problem…

That seems to me to be a bit of a problem... hopefully there's a way around this.



RockfordLhotka replied on Tuesday, January 29, 2008

I think I have a solution – conceptually anyway.

 

Though you can’t guarantee the order in which static initialization will occur, there’s no doubt that by the time the first instance method is called all static initialization has taken place.

 

So what I can do is passively accumulate the PropertyInfo objects into Type-indexed lists.

 

Then, when the first attempt is made to get/set a property I can walk up the inheritance hierarchy and ensure the Index properties of all PropertyInfo objects are set, with the top-level base class’s properties starting at 0 and counting up, then the next subclass, and the next, all the way out to yours.

 

What a cool algorithm!

 

Rocky

 

 

From: skagen00 [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 10:21 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: CSLA .NET 3.5 Beta 1 available

 

Rocky: I could see where properties in abstract classes could be problematic. You probably need to register them in the subclass, even though the implementation is in the base class. Interesting problem…

That seems to me to be a bit of a problem... hopefully there's a way around this.



skagen00 replied on Tuesday, January 29, 2008

I'm very interested to see how this might work!

I have three classes in the hierarchy I'm working with.

1) Entity<T>, which includes an Id and timestamp information for user creation and modification

2) ProfileName<T>, which encompasses organization and individual names.

3) IndividualName (which includes things such as first name, etc.)

What was interesting is that I was getting the registerproperty calls firing for #1 and #3, but the mFieldData was getting initialized then (excluding the two properties for #2) and then the register property calls for #2 would fire. Obviously this would explain why subsequent requests would work - the mFieldData got initialized properly with the entire list.

I really appreciate you taking this issue into consideration so quickly. If you have a solution you'd like me to try within my code, just tell me which files to grab from your source and I'll verify it solves the problem I was encountering. I'll watch this thread or my e-mail is chlusak@microedge.com.

Whenever you find the time, of course. As always, thanks!

Chris

p.s. I have a number of hierarchical cases like this - such as profiles including Individuals and Organizations, etc.

RockfordLhotka replied on Tuesday, January 29, 2008

This is the reason for beta releases – I really appreciate your feedback and help getting it all working!!

 

I’ll let you know when there’s something to test. You might find it easiest to download TortoiseSVN and just grab the files directly from my repository

 

http://www.lhotka.net/cslanet/Repository.aspx

 

Rocky

 

 

From: skagen00 [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 11:24 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: RE: CSLA .NET 3.5 Beta 1 available

 

I'm very interested to see how this might work!

I have three classes in the hierarchy I'm working with.

1) Entity<T>, which includes an Id and timestamp information for user creation and modification

2) ProfileName<T>, which encompasses organization and individual names.

3) IndividualName (which includes things such as first name, etc.)

What was interesting is that I was getting the registerproperty calls firing for #1 and #3, but the mFieldData was getting initialized then (excluding the two properties for #2) and then the register property calls for #2 would fire. Obviously this would explain why subsequent requests would work - the mFieldData got initialized properly with the entire list.

I really appreciate you taking this issue into consideration so quickly. If you have a solution you'd like me to try within my code, just tell me which files to grab from your source and I'll verify it solves the problem I was encountering. I'll watch this thread or my e-mail is chlusak@microedge.com.

Whenever you find the time, of course. As always, thanks!

Chris

 



RockfordLhotka replied on Tuesday, January 29, 2008

I think the fix is in. Changes to files:

If you can see if this solves your issues that'd be awesome. I have a unit test with inheritance now, and it passes that unit test, so I think we're good.

skagen00 replied on Tuesday, January 29, 2008

Unfortunately there appear to still be issues (at least for me). It's hard to debug but I'm working through trying to understand it all. Hope to be able to provide more feedback for you soon.

RockfordLhotka replied on Tuesday, January 29, 2008

Maybe I should be clear about what I made it support.

 

You can have a base class. The base class defines properties and registers them all by itself. Those properties are registered against the base class type of course:

 

public class Base<T> : BusinessBase<T> where T: Base<T>

{

  private static PropertyInfo<string> NameProperty = RegisterProperty<string>(typeof(Base<T>), new PropertyInfo<string>(“Name”));

  // …

}

 

The subclass registers its properties against its own type:

 

public class EndClass : Base<EndClass>

{

  private static PropertyInfo<string> TitleProperty = RegisterProperty<string>(typeof(EndClass), new PropertyInfo<string>(“Title”));

  // …

}

 

Then you use these:

 

EndClass x = new EndClass();

x.Name = “fred”;

x.Title = “CEO”;

 

Rocky

 

 

 

From: skagen00 [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 2:09 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: RE: RE: CSLA .NET 3.5 Beta 1 available

 

Unfortunately there appear to still be issues (at least for me). It's hard to debug but I'm working through trying to understand it all. Hope to be able to provide more feedback for you soon.



skagen00 replied on Tuesday, January 29, 2008

Thank you, that's exactly the scenario I'm looking to accomplish. Hope to have some constructive feedback on what I'm experiencing once I have a grasp of exactly what that is :)

 

Bob Matthew replied on Wednesday, February 20, 2008

Rocky,

 

I’m experiencing some interesting behavior with the PropertyInfo objects’ Index property.  Specifically, inside of the data portal, which has the exact same assemblies as outside of the data portal, the Index for each PropertyInfo of a business object is different.  This has the ability to call throw an InvalidCastException (because a string property can’t be an int property) or worse yet, not exception at all.

 

I should probably mention that this is most likely due to the fact that I have a custom base class (which for lack of a better name is called BusinessBaseX) that has a single PropertyInfo object (which is common to my objects) being registered.

 

I read through the link you posted previously from the MSDN found here: http://msdn2.microsoft.com/en-us/library/aa645758(VS.71).aspx

 

If you look closely at the beginning of the article, it says that when the static fields are initialized they “are executed in the textual order in which they appear in the class declaration”.  In other words, the only way that they could fire in a different order is by having different versions of an assembly on either side of the portal.

 

This being the case, I wonder if I might re-suggest a re-consideration of the methodology that I was using a few weeks ago before 3.5 Beta 1.  This methodology was the following for the BusinessBase class.

 

// dictionary which maps the property to the index of an array

private static Dictionary<IPropertyInfo, int> _properties = new Dictionary< IPropertyInfo, int>();

 

// instance values of each property

private IFieldData[] _values;

 

I will keep you posted on more of the specifics of the problem as I debug as well as potential workarounds.

RockfordLhotka replied on Wednesday, February 20, 2008

I very much doubt the issue is actually with the order of properties being wrong within a specific type, because you’ll note that the propertyinfo objects are sorted within a type. It doesn’t matter in what order the propertyinfo fields are initialized, they end up in the same order regardless. Unless I missed something of course J

 

I don’t trust that MSDN article’s assertion. I know for a fact that C# and VB act differently in how fields/properties are managed in some cases – VB sorts and C# does them in order (or maybe it was the other way around). Don’t ask me why, and I don’t know that this difference includes static fields – but order-of-initialization seems like a risky assumption to make in any case.

 

Hence the sorting, so there’s a guaranteed order.

 

My guess is that it is a different problem – specifically the one I was fighting with the auth code, where you can’t predict the order in which the types in your inheritance hierarchy will initialize. In fact, it is quite possible for an intermediate type (one in the middle of the hierarchy) to not initialize until very late in the process – after both the business subclass and Csla.Core.BusinessBase have initialized. There appears to be no direct solution to this problem that can be implemented purely within CSLA – the issue is too low-level within .NET.

 

The solution I’ve come up with to the problem is somewhat of a hack, and involves setting the value of a static field from within the constructor (which solves the auth issue).

 

Of course deserialization doesn’t run constructors, so I’m guessing this static field must be set within OnDeserialized() as well. That may be true for the auth case as well (probably is now that I think about it).

 

If my theory is right, you can add code like this to your class:

 

[Serializable]

public abstract class BusinessBaseX : …

{

  private static int _dummy;

 

  private BusinessBaseX()

  {

    _dummy = 42;

  }

 

  protected override void OnDeserialized()

  {

    _dummy = 42;

  }

}

 

That’ll force the initialization of the static fields in this intermediate class during the deserialization process, forcing the propertyinfo field(s) to be initialized on the app server during deserialization.

 

The trick is that _dummy must be declared in each specific intermediate class, because static fields are initialized on a per-type basis. There’s no way (short of maybe some reflection hacks – and even that would require extra code in each intermediate class) for Csla.BusinessBase to ensure that all static fields are initialized in the inheritance hierarchy. But this should do the trick.

 

Rocky

Bob Matthew replied on Wednesday, February 20, 2008

Sure enough, having a _dummy static variable in the intermediate class took care of it.  I had a dummy var in my most base class (which didn't have any PropertyInfo objects) and in my business object classes.  I figured it was some .NET Framework quirk, like you said.

You may want to put this into your documentation because, per my understanding, it's still considered a CSLA best practice to have our own intermediate classes from which we inherit, rather than inheriting directly from BusinessBase.

RockfordLhotka replied on Wednesday, February 20, 2008

Oh you can bet this’ll get discussed in the book J

 

Rocky

 

From: Bob Matthew [mailto:cslanet@lhotka.net]
Sent: Wednesday, February 20, 2008 8:32 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: CSLA .NET 3.5 Beta 1 available

 

Sure enough, having a _dummy static variable in the intermediate class took care of it.  I had a dummy var in my most base class (which didn't have any PropertyInfo objects) and in my business object classes.  I figured it was some .NET Framework quirk, like you said.

You may want to put this into your documentation because, per my understanding, it's still considered a CSLA best practice to have our own intermediate classes from which we inherit, rather than inheriting directly from BusinessBase.



RockfordLhotka replied on Tuesday, January 29, 2008

I found a null ref issue in FieldDataManager - the fix is in svn now - perhaps that'll help?

skagen00 replied on Tuesday, January 29, 2008

I know this is of very little help thus far but I'm still having perhaps some sort of a timing issue.

When GetConsolidatedList is getting run, it happens after 13 of 15 properties for IndividualName have been registered. 8 for the IndividualName class, 5 for Entity<T>, but not the 2 for ProfileName<T>. So, it ends up with an incomplete list.

Entity<T>(5)----ProfileName<T>(2)----IndividualName(8)

Why the five fire for Entity<T> but not the two for ProfileName<T>, you got me. I certainly haven't abandoned this and I'll give you whatever useful feedback I can.

 

 

 

skagen00 replied on Tuesday, January 29, 2008

The moment I changed my validation rules in ProfileName<T> to use the propertyinfo overloads, I started getting the registerproperties called for that class, but not Entity<T>'s register properties now. (i.e. it's registering 10 properties - 8 + 2). Don't ask me why that happened.

IndividualName ends up getting it's fieldmanager/propertylist of 10 items prior to the entity<T> class registering its properties now...so when trying to load the property of SystemId on a fetch (this is an entity<T> property) it croaks out and says:

[Csla.PropertyLoadException] = {"Property load or set failed for property SystemId (Index was outside the bounds of the array.)"}

FWIW, more information as I have it. (Clogging up your beta thread :))

 

 

RockfordLhotka replied on Tuesday, January 29, 2008

No, this helps a lot.

 

It appears there are some odd things with static initialization where it is possible for instance code to run before static fields have been initialized. This flies in the face of my understanding, so I need to do some research on this to see whether it is a .NET 3.5 compiler change or something…

 

But I can walk through the debugger and watch instance code running before the static field initializers – in the same type!! Unreal!

 

So you are right, it is a timing issue.

 

One solution appears to be to put the RegisterProperty() calls into a static constructor, because that still runs before any instance code within a type. But that’s a pretty lame solution imo…

 

Rocky

 

 

From: skagen00 [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 3:56 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] CSLA .NET 3.5 Beta 1 available

 

I know this is of very little help thus far but I'm still having perhaps some sort of a timing issue.

When GetConsolidatedList is getting run, it happens after 13 of 15 properties for IndividualName have been registered. 8 for the IndividualName class, 5 for Entity<T>, but not the 2 for ProfileName<T>. So, it ends up with an incomplete list.

Entity<T>(5)----ProfileName<T>(2)----IndividualName(8)

Why the five fire for Entity<T> but not the two for ProfileName<T>, you got me. I certainly haven't abandoned this and I'll give you whatever useful feedback I can.

 

 

 



vdhant replied on Tuesday, January 29, 2008

Not that i have had much of a chance to get deep down into .net 3.5 but if it is possible for instance code to run before static fields have been initialized this would be a big problem. Not only CSLA but for other things as well. There are plenty of situations that rely on the static fields to be initialized before instance code runs...
Rocky, you might have to put your hard hat on and have a talk to the guys on the hill if this is the case
;)

skagen00 replied on Tuesday, January 29, 2008

Well, if worse comes to worse, the static constructor seems to be an effective solution in my case.

 

RockfordLhotka replied on Tuesday, January 29, 2008

Wow!

 

http://msdn2.microsoft.com/en-us/library/aa645758(VS.71).aspx

 

It turns out that static initializers are only guaranteed to run before the first use of a static field. Instance code can run all it wants before the static fields are initialized.

 

Another solution is to include an empty static constructor in your base class. At least you don’t need to move the RegisterProperty() calls there – just having an empty static ctor is enough for force the behavior we need.

 

But implementing a static ctor forces the compiler to inject a bunch of code around your class, which can be a perf issue (or so I’ve read). So it is best to avoid static ctors if possible.

 

So here’s a solution I just tested that seems to work (though it is clearly a hack). If the rule is that a static field must be used, and we know that the instance ctors all run up the inheritance hierarchy, you can have your instance ctors “touch” a static field in each base class:

 

public class Base<T> …

{

  private static int _dummy;

 

  protected Base()

  {

    _dummy = 0;

  }

}

 

As the instance ctors run in each class in your inheritance hierarchy, you are guaranteed that this dummy field is set. That forces initialization of all static fields in the class, thus ensuring that all the base classes have initialized their static fields by the time your subclass’s ctor runs, and thus before any chance of trying to get at the consolidated list of registered properties.

 

Rocky

 

 

 

From: Rockford Lhotka [mailto:rocky@lhotka.net]
Sent: Tuesday, January 29, 2008 4:26 PM
To: 'cslanet@lhotka.net'
Subject: RE: [CSLA .NET] CSLA .NET 3.5 Beta 1 available

 

No, this helps a lot.

 

It appears there are some odd things with static initialization where it is possible for instance code to run before static fields have been initialized. This flies in the face of my understanding, so I need to do some research on this to see whether it is a .NET 3.5 compiler change or something…

 

But I can walk through the debugger and watch instance code running before the static field initializers – in the same type!! Unreal!

 

So you are right, it is a timing issue.

 

One solution appears to be to put the RegisterProperty() calls into a static constructor, because that still runs before any instance code within a type. But that’s a pretty lame solution imo…

 

Rocky

 

 

From: skagen00 [mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 3:56 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] CSLA .NET 3.5 Beta 1 available

 

I know this is of very little help thus far but I'm still having perhaps some sort of a timing issue.

When GetConsolidatedList is getting run, it happens after 13 of 15 properties for IndividualName have been registered. 8 for the IndividualName class, 5 for Entity<T>, but not the 2 for ProfileName<T>. So, it ends up with an incomplete list.

Entity<T>(5)----ProfileName<T>(2)----IndividualName(8)

Why the five fire for Entity<T> but not the two for ProfileName<T>, you got me. I certainly haven't abandoned this and I'll give you whatever useful feedback I can.

 

 

 



ajj3085 replied on Wednesday, March 05, 2008

Rocky,

I was hoping you could shed some more light on this, because I hit a wierd problem with static fields.  I was trying to eliminate a static constructor in my application, and I found something weird.

Having a field declared as such:
private static List<object> myList = new List<object>();

I would expect to hit the problem you describe.  The only cavet is that when I checked with Reflector.Net to ensure my static ctor was gone, I found that the above produces this code:

private static List<Object> myList;

static MyClass() {
    myList = new List<object>();
}

So is that actually what the compiler is doing, or is that how Reflector is interperating it?  I'm confused now, because based on your comments above I wouldn't expect the code genereated above.  So something is fishy.

Thanks
Andy

RockfordLhotka replied on Thursday, March 06, 2008

I’m not sure I can shed a lot of light. You should find Brad Abram’s blog post(s) on this topic to get the real scoop. The details are complex and subtle.

 

Rocky

 

 

From: ajj3085 [mailto:cslanet@lhotka.net]
Sent: Wednesday, March 05, 2008 1:11 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: CSLA .NET 3.5 Beta 1 available

 

Rocky,

I was hoping you could shed some more light on this, because I hit a wierd problem with static fields.  I was trying to eliminate a static constructor in my application, and I found something weird.

Having a field declared as such:
private static List<object> myList = new List<object>();

I would expect to hit the problem you describe.  The only cavet is that when I checked with Reflector.Net to ensure my static ctor was gone, I found that the above produces this code:

private static List<Object> myList;

static MyClass() {
    myList = new List<object>();
}

So is that actually what the compiler is doing, or is that how Reflector is interperating it?  I'm confused now, because based on your comments above I wouldn't expect the code genereated above.  So something is fishy.

Thanks
Andy


Skafa replied on Thursday, March 06, 2008

Rocky,

The link you gave us (http://msdn2.microsoft.com/en-us/library/aa645758(VS.71).aspx), says:
If a static constructor exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.


and gives an example using an empty static constructor..

so... what's with that _dummy field ;-)

RockfordLhotka replied on Thursday, March 06, 2008

You tell me…

 

Clearly this stuff is complex, and there may be differences between .NET 1, 2 and 3?

 

I know there is a perf consequence to having a static constructor (cctor) in a class, and so they should be avoided.

 

It would appear then, that you can force initialization in two ways:

 

1.       Implement a cctor and pay the perf cost

2.       Somehow set a static field to a value

 

The _dummy field is an attempt (that works) to go with option #2.

 

Of course this doesn’t appear to match with what reflector is showing (Andy was it?), so that’s confusing – and I don’t have an answer for that…

 

Rocky

 

 

From: Skafa [mailto:cslanet@lhotka.net]
Sent: Thursday, March 06, 2008 4:24 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: CSLA .NET 3.5 Beta 1 available

 

Rocky,

The link you gave us (http://msdn2.microsoft.com/en-us/library/aa645758(VS.71).aspx), says:

If a static constructor exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.



and gives an example with an empty static constructor..

so... what's with that _dummy field ;-)


ajj3085 replied on Friday, March 07, 2008

Here's what I've found.

Using reflector, it looks like ANY field initializes are simply compiler magic.  Instance fields initlization is done by injecting the code to initalize BEFORE any code you place in the constructor.  It works the same for static fields as well. 

ildasm seems to confirm this.

using System;

namespace ConsoleApplication24 {
    class Program {
        private static int myVal = int.MinValue;

        static void Main( string[] args ) {
            Console.WriteLine( myVal );
        }
    }

    internal class TestClass {
        private static int myInt1 = int.MaxValue;
        private int myInt2 = int.MinValue;

        public TestClass() {
            Console.WriteLine( myInt1 );
        }
    }
}

Here's what the ctor for TestClass looks like:
.method public hidebysig specialname rtspecialname
        instance void  .ctor() cil managed
{
  // Code size       32 (0x20)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4     0x80000000
  IL_0006:  stfld      int32 ConsoleApplication24.TestClass::myInt2
  IL_000b:  ldarg.0
  IL_000c:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0011:  nop
  IL_0012:  nop
  IL_0013:  ldsfld     int32 ConsoleApplication24.TestClass::myInt1
  IL_0018:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_001d:  nop
  IL_001e:  nop
  IL_001f:  ret
} // end of method TestClass::.ctor

IL_0006 was injected into the constructor.  The same thing is done for the Program class; the static field initializer results in a static ctor being built:

.method private hidebysig specialname rtspecialname static
        void  .cctor() cil managed
{
  // Code size       11 (0xb)
  .maxstack  8
  IL_0000:  ldc.i4     0x80000000
  IL_0005:  stsfld     int32 ConsoleApplication24.Program::myVal
  IL_000a:  ret
} // end of method Program::.cctor

The same thing happens regardless of whether I'm targeting .Net 2 or 3+, although I haven't tried with VS2005.

So, no magic to field initializes, its a compiler trick.  Looking at the IL, I am assuming that ldsfld (Load Static Field) somehow ensures that the .cctor is called.

So... I haven't been able to find out how or why constructors are called.  I guess somehow it's possible constructors aren't called during deserialization, but accessing a static field (ldsfld) causes them to run.  Maybe someone else has time to look into this more?

I know I had a wierd issue where if a classes static or instance fields were NEVER accessed, and the type was being built during deserialization, the static fields weren't initalized.  But if the user did something that caused the type to be accessed, the fields were initialized. 

xal replied on Monday, March 10, 2008

Yes Andy, you are correct on that. I saw this same pattern when we were discussing static rules for Csla 2.1...
Back in that time (and through the many iterations static rules had before they became what they are today) at some point, rocky made a requirement to load rules in the static cctor. That had a big downside and eventually he dropped that concept in favor of loading rules the first time a class was instanced.

I would have thought this was a similar case, but clearly it's not, right?

I also remember that around that same time I was trying to find a way to trigger static initialization so that inheritance would be well supported (when we were using static cctors) and I actually did find a sort of hacky way of doing it, but the upside to that was that it was locked inside csla, so it didn't involve creating a static field in every class. I'll see if I can find that amongst my really really old emails.


Andrés

xal replied on Monday, March 10, 2008

I finally found it!
Here it is:
http://forums.lhotka.net/forums/post/1478.aspx

Esentially, that ensures that the class has been initialized. It does involve reflection though.

Another way to solve it may be to use the pattern in the rules manager: have an overridable method like.


Protected Overrides Sub RegisterProperties()
    MyBase.RegisterProperties()
    MyBase.PropertyManager.RegisterProperty(<pass field info here>)
End Sub


Note: I've been trying to get the latest csla, but Rocky's site seems to be down at the moment. I'm not familiarized with the code or how the current implementation works, but the problem you are talking about reminded me of those things... so, sorry if I'm barking up the wrong tree here :)


Andrés

xal replied on Monday, March 10, 2008

Ok, I've seen in another thread how it's meant to work:

Public Class MyClass
    Private Shared NameProperty As PropertyInfo(Of String) = _
    RegisterProperty(Of String)(GetType(MyClass), New PropertyInfo(Of String)("Name", "friendly name of property", String.Empty))
End Class


Rocky, back when we were discussing the loading of rules in the static cctor, one of the very good reasons we moved away from it was because of the need of having to pass the type.
We agreed at that time that it was error prone (copy pasting anyone?) and unsafe, since you could end up adding rules (in this case properties) to a type other than the one you're loading. Debugging that would be a nightmare!

Why not reuse the same pattern and go with the RegisterProperties() pattern in my previous post.

The upsides are:
-You don't have to pass the type (which means it's less error prone and you type less code).
-It follows a familiar pattern.
-You don't need to worry about order of initialization of static fields or cctors.

The downside:
-You have to do declaration and initialization of PropertyInfo in 2 separate places.


Here's how it could look (also, adding an overload for Register Property similar to the ones we have for rules):

Public Class MyClass
    Private Shared NameProperty As PropertyInfo(Of String)
   
    Protected Overrides Sub RegisterProperties()
        MyBase.RegisterProperties()
        NameProperty = RegisterProperty(Of String)( _
            "Name", "friendly name of property", String.Empty)
    End Sub

End Class

Overall, much simpler and without the issues you were mentioning. What do you think?

Andrés

RockfordLhotka replied on Monday, March 10, 2008

I don’t want to declare and initialize propertyinfo in different locations. Or at least I don’t want to force it to be done that way. The whole point of this was/is to reduce and simplify code.

 

Rocky

 

xal replied on Tuesday, March 11, 2008

While I agree it might be a pain to have to instance them in a different place, I think that the benefits far surpass the cons of the approach.

Having to fall back to hacks like requiring the user to create a field and calling it in the constructor is bad, and forcing to run the static constructor or reading fields through reflection like in the example in my previous link isn't any better really...

So I insist: the pattern is well known and accepted, it saves you from having to pass the type (so it does make it somewhat simpler, shorter and less error prone than the current approach) and last but not the least you don't have to hack anything for inheritance to work.

Back in the day, you had Asserts for rules, which did everything in one line. At some point you separated the declaration from the assignment of the rule by moving the body of a rule to a method and having a way to attach it to a property through the AddRule method, and this is quite a similar scenario: declaration and instantiation on separate places.


I realize it's late on the release cycle (beta), but I suppose it would be better to break now than later. Or even if you didn't want to break the beta you could support both approaches (which is probably painful, I know).

Anyway, that's my 2 cents. :)

Andrés

skagen00 replied on Tuesday, March 11, 2008

I personally like the single line declaration of managed properties partially because of the late cycle - we started architecting around the last preview and have altered course due to a change prior to beta 1. While I'm not thrilled with the hack it's really a pretty inconsequential thing - it's only being required on cases where inheritence is being used.

The declaration we end up using is pretty streamlined - we leverage a method in our base class to accomodate passing in the type - after all it's just T.

private static CompanyPropertyInfo<string> _profileName = RegisterCompanyProperty<string>("ProfileName", "Profile Name");

CompanyPropertyInfo isn't the actual name of our property info but it extends the base property info and provides some additional behavior.  To me, the above line is very simple and the simple inclusion of the hack for my abstract base classes, I can deal with that.

So I would throw a vote in for not changing the current approach, with all due respect to Andres.

Chris

 

xal replied on Tuesday, March 11, 2008

Hi Chris!
Yes, I realize there might be a couple dozen projects (maybe more, maybe less) that are relying on the way it works right now. Some bigger, some smaller. But still a few compared to the hundreds that would be using it once it is an official release, when it's harder to make such a change.
Still, I would argue that both approaches can be maintained if required, and if it's not, you could even maintain it in your own version of csla.

Also, I'd bet most of those projects are using code generation, so making the change should be straight forward for those, since it won't change the basic way in which everything works...

When 2.1 was being baked we were using the latest cvs at the company I worked for and we had to change the business rules a couple of times too many (on a rather large project), but it IS one of the risks of using code that's not yet final...

Andrés

RockfordLhotka replied on Tuesday, March 11, 2008

xal:
I finally found it!
Another way to solve it may be to use the pattern in the rules manager: have an overridable method like.

That would probably work.

However, I think it is important to be relatively consistent with Microsoft. Microsoft has defined the dependency property concept for WPF and WF, and I modeled this approach after what they did. For better or worse, they require passing in the type of the container.

You should be aware that nothing forces you to call RegisterProperty() on the field declaration. If you want to call it in some other location you surely could. Other locations might include a static constructor, or in the Initialize() method (though you'd need to make sure to only do the initialization once per AppDomain. Something like:

public class Foo : BusinessBase<Foo>
{
  private static bool _propertiesLoaded;
  protected override void Initialize()
  {
    base.Initialize();
    if (!_propertiesLoaded)
    {
      _propertiesLoaded = true;
      // register properties here
    }
  }
}

Of course the reality is that setting _propertiesLoaded would trigger all the RegisterProperty() calls on static field declarations too Smile [:)]

xal replied on Wednesday, March 12, 2008

Very true, which is why I suggest that the FieldManager / PropertyInfoManager does the same thing the ValidationRuleManager does in escence... All you need to do is provide an overridable method that runs when there is no IPropertyInfo list associated with the current type in the cache and call it from within the constructor and OnDeserialized (just like with validation rules)....

If you give us that (preferably with an overload for RegisterProperty that gets the type automatically**), nothing else needs to change. Anybody could be using that approach or the wpf like one.

Note: Rocky, on your quote from my previous post those 2 lines were about 2 different things, if you check the thread I pointed to, you'll see the workaround that could (but not necessarily should) be implemented in csla to solve the inheritance problem without needing to go through an overridable instance method like I propose or recurring to reading a static field in every constructor. The second line was about the overridable method suggestion.

**Note: that should probably be an instance method.

Andrés

ajj3085 replied on Wednesday, March 12, 2008

Well, this thread has discussed several solutions to the problem, but I'm still curious as to the cause.  Rocky, do you think you could ask one of your MS contacts what causes the fields to NOT initialize?  It seems like a bug in the framework.

Skafa replied on Wednesday, March 12, 2008

ajj: It's by design

See this post:
http://forums.lhotka.net/forums/permalink/21959/21871/ShowThread.aspx#21871

ajj3085 replied on Wednesday, March 12, 2008

No, it's not.  From that link "If a static constructor (Section 10.11) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class."

Well, if that bolded part were true, we wouldn't need any of these hacks to cause the variables to initalize.  That's actually the whole problem; the fields are not initialized when we go to use them under certain conditions.  By use I would assume either reading or writing the field.

Skafa replied on Wednesday, March 12, 2008

,,Well, if that bolded part were true, we wouldn't need any of these hacks to cause the variables to initalize.  That's actually the whole problem; the fields are not initialized when we go to use them under certain conditions.  By use I would assume either reading or writing the field.''

The behaviour stated in the documentation is correct. No bugs here. The problem with Csla 3.5 is that the whole propertie registering relies on the fact that static fields múst be initialized (which, as stated there, depends on accesing a static field).

So the Csla instance code - which needs the properties to have registered themself using RegisterProperty() - runs before the actual static fields having initialized themself.

The problem is not that "in rare cases" static fields don't get initialized. The real problem is that csla's instance code ássumes that these static fields are always initialized (which, as the documentation states, is not true).

edit: so in our case: static fields aren't used before the instance code, that relies on those static fields beeing initialized. That's why a dummy static field could be a possible solution.

RockfordLhotka replied on Wednesday, March 12, 2008

Skafa is exactly right.

In an inheritance scenario, your end subclass (the actual business type) gets initialized because it is the type being created, and so the code almost certainly interacts with one or more static fields in that class.

And the CSLA base classes (Core.BusinessBase in particular) gets initialized because it interacts with its own static fields.

But no code interacts with any static fields in any classes between Core.BusinessBase and your end business class. So there's no guaranteed trigger that would cause those static fields to initialize prior to instance code getting to run.

Nor can CSLA really automate that process without some expensive use of reflection. The only thing I can think of would be to reflect against every class in the inheritance hierarchy and try to arbitrarily set the first static field I find in each class. That'd be both expensive and VERY error-prone (probably would break many apps).

You can force it by implementing either a static constructor, or using the _dummy field technique. Either one will force the static fields to initialize in that class.

Xal is right, I could implement a dual solution - what we have now (which I like) and something more like validation rules. That's double the effort in testing, maintenance and support for me.

I'm already nervous about the explosion in options for doing things - I feel like Microsoft... Wink [;)] Look at all the ways to declare a property now - and I need to support, maintain and regression test all of them each time I change something in the framework. A couple more expansion changes like that and I'll be unable to keep up.

And ultimately there's my schedule. I'm so booked between now and mid-May that doing something like Xal proposes would probably have to wait until then. And it is a big change, so it would require a Beta 3. So then 3.5 wouldn't come out until mid-June. That will make for some unhappy people I'm sure.

Additionally, I am starting the 2008 book, and this would delay that too - which would push the book beyond the realistic publication date, so the book would be canceled.

In short, I'm not making any changes of this magnitude to solve an edge case that already has a couple solutions - not when it means a multi-month delay in release and cancelation of the 2008 book (remember - that's how I fund all this work - no book = no sales = no funding = bad!).

ajj3085 replied on Wednesday, March 12, 2008

I wasn't suggesting any changes, just pointing out that static field initalizes result in a static ctor being created.. so to truely avoid the perf hit you need to find another way to initialize the fields.

The original problem I was having (I dug into it because I fixed it a while ago) was that static constructors were being executed on the remoting server but not on the client machine.  I fixed it the same way you seem to handle the problem for validation rules, by calling the method which initialized the fields in an OnDeserialized call. 

I thought there was a seperate issue when I was expecting a static field to be set (which was supposed to be set by a field initalizer), but when I attempted to use it I got a NullReferenceException.  I can't find what this was, and unfortunately I don't have any source control because I haven't checked in the feature I'm working on.  Or maybe I'm dizzy from the DST change.  Smile [:)]

Bob Matthew replied on Saturday, February 02, 2008

Rocky,

One thing we've noticed with the new ContextManager class is the "new()" requirement for the template parameter.

We have found that a DataContext need not have a public, parameterless constructor, which is contrary to the "new()" condition of the ContextManager.  Specifically, when you create a new Linq To Sql class and then drag some tables/stored procs, etc to the designer, you can then set the Connection property under the Properties section to "(None)".  This removes the default, parameterless constructor from the DataContext.

It would seem that stipulating a DataContext as a template condition, which you already do, would suffice.

On a different note, on the "nice to have" side of things, it would be great to have a GetManager overload that specified the "name" of the connection to retrieve from the configuration, rather than the connection string itself.

A simple overload like this would perhaps serve the purpose:

GetManager(string connectionString, bool isConnectionName);

The function would then "resolve" the provide string from a name to the actual connection string and then provide that to your existing GetManager function.

Other than that, CSLA 3.5 is working great!

vdhant replied on Monday, February 04, 2008

Hey Rocky if you have not already you may want to take a look at this thread in regards to a possible feature that would be of use and a possible problem with the change that was made to the loading of type auth rules in regards to inheritance. Note i have not tested to see if it is an issue but thinking it through it possible could be.

Anthony

Copyright (c) Marimer LLC