CSLA .NET

From Rockford Lhotka's Expert C# 2008 and VB 2008 Business Objects books

Problem with the order of fields in derived classes.

rated by 0 users
This post has 7 Replies | 2 Followers

Not Ranked
Posts 3
Entophysalis Conferta Posted: Mon, Dec 29 2008 10:38 PM
I have following inheritance structure of business objects:

1. public abstract class BusinessObject<T> : BusinessBase<T> where T : BusinessObject<T>
2. public abstract class AuthorizedUser : BusinessObject<AuthorizedUser>

+ Code
+ Email
+ Kind
+ Login
+ Name
+ Password
+ Phone
+ PreferredContact (enum ContactMethods { Email, Phone })

All properties is managed (using RegisterProperty, GetProperty, SetProperty).

3. public class AdminUser : AuthorizedUser
4. public class ClinicUser : AuthorizedUser

+ City
+ Comment
+ ConvenientTime
+ Fax
+ PracticeName
+ PracticeWebsite
+ State
+ Zip

All properties is managed.

With fresh database, I create admin user. I have AdminUser's field list as:

Field index : Field name
-------------------------
0 : Code
1 : Email
2 : Kind
3 : Login
4 : Name
5 : Password
6 : Phone
7 : PreferredContact

Then I load user list, create clinic user. I have ClinicUser's field list as:

Field index : Field name
-------------------------
0 : City
0 : Code
1 : Comment
2 : ConvenientTime
1 : Email
2 : Fax
2 : Kind
3 : Login
4 : Name
5 : Password
6 : Phone
7 : PracticeName
8 : PracticeWebsite
7 : PreferredContact
8 : State
9 : Zip

I got an exception from validation rule for [PracticeName]:
System.InvalidCastException: Unable to cast object of type 'ContactMethods' to type 'System.String'.

I temporarily fix that by:
+ Add inheritance level to field friendly name
+ Call SyncFieldIndex procedure before every action of create, insert.

        protected virtual void SyncFieldIndex()
        {
            List<Csla.Core.IPropertyInfo> list = FieldManager.GetRegisteredProperties();
            list.Sort(ComparePropertyInfo);
            for (int idx = 0; idx < list.Count; idx++)
            {
                list[idx].Index = idx;
            }
        }

        private int ComparePropertyInfo(Csla.Core.IPropertyInfo x, Csla.Core.IPropertyInfo y)
        {
            int result = string.Compare(x.FriendlyName, y.FriendlyName);
            if (result != 0) return result;
            return string.Compare(x.Name, y.Name);
        }

I would like to confirm that this is a bug or my wrong use of framework. Which is best way to overcome this problem.

Thanks for your help.

Top 10 Contributor
Posts 3,715
Andy replied on Tue, Dec 30 2008 7:27 AM
Hi,

I hit this problem too.  It has to do with the multiple levels of inheritence.  Search this forum for _dummy or dummy to find the solution, or check out the C# 2008 Business Objects book, page 248, RegisterProperty and Inheritance.
Not Ranked
Posts 3
ajj3085:
Hi,

I hit this problem too.  It has to do with the multiple levels of inheritence.  Search this forum for _dummy or dummy to find the solution, or check out the C# 2008 Business Objects book, page 248, RegisterProperty and Inheritance.


Thanks for your help. I have read _dummy related threads. I have tried _dummy trick but it did not help.

        #region Dummy Workaround

        private static int _dummy;

        protected BusinessObject()
        {
            _dummy = 0;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            base.OnDeserialized(context);
            _dummy = 0;
        }

        #endregion


        #region Dummy Workaround

        private static int _dummy;

        protected AuthorizedUser()
        {
            _dummy = 0;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            base.OnDeserialized(context);
            _dummy = 0;
        }

        #endregion


        #region Dummy Workaround

        private static int _dummy;

        protected AdminUser()
        {
            _dummy = 0;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            base.OnDeserialized(context);
            _dummy = 0;
        }

        #endregion


        #region Dummy Workaround

        private static int _dummy;

        protected ClinicUser()
        {
            _dummy = 0;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            base.OnDeserialized(context);
            _dummy = 0;
        }

        #endregion

Not Ranked
Posts 3
I have read "C# 2008 Business Objects" book, page 248. I have tried both ways: adding static constructor and initializing dummy static field. But it still did not help.

        #region Dummy Workaround

        private static int _forceInit;

        static BusinessObject() { }

        protected BusinessObject()
            : base()
        {
            _forceInit = 1;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            _forceInit = 1;
        }

        #endregion


        #region Dummy Workaround

        private static int _forceInit;

        static AuthorizedUser() { }

        protected AuthorizedUser()
            : base()
        {
            _forceInit = 1;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            _forceInit = 1;
        }

        #endregion


        #region Dummy Workaround

        private static int _forceInit;

        static AdminUser() { }

        protected AdminUser()
            : base()
        {
            _forceInit = 1;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            _forceInit = 1;
        }

        #endregion


        #region Dummy Workaround

        private static int _forceInit;

        static ClinicUser() { }

        protected ClinicUser()
            : base()
        {
            _forceInit = 1;
        }

        protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
        {
            _forceInit = 1;
        }

        #endregion

Top 10 Contributor
Posts 1,244
JoeFallon1 replied on Wed, Dec 31 2008 11:37 AM

Did you add the _dummy code in every single level of your inheritance chain? You have to do that.

Joe

 

Top 25 Contributor
Posts 282
rfcdejong replied on Tue, Oct 13 2009 7:05 AM
Sorry for replying on an old post, but i just ran into this problem.

We removed the _dummy or _forceInit from our inheritance classes and indeed the order of the fields are wrong between the FieldManager and the PropertyInfo.Index

I thought it would had been "fixed" in a new version.

I guess i'm mistaken about it being "fixed"
Top 10 Contributor
Posts 7,309

It should be fixed in current versions - there's even a unit test that confirms the fix.

The fix was to use reflection to walk the inheritance hierarchy, accessing a static field in each class, thus triggering the static field initialization in each class.

The method is called ForceStaticFieldInit() in the FieldDataManager class. You could put a breakpoint in that method to make sure it is being hit on the first use of each type - on the client and on the server.

Rocky

Top 10 Contributor
Posts 7,309

Oh, one other thing.

If you are using Silverlight the rules are a little different because private reflection isn't possible. So the fix is in CSLA .NET for Silverlight, but it can only work if your PropertyInfo<T> fields are public in scope, not private. If they aren't public, then the reflection code can't see the fields and thus can't trigger the field initialization.

Rocky

Page 1 of 1 (8 items) | RSS

Please contact Magenic for your .NET consulting
and CSLA .NET mentoring needs.
Please consider making a donation to help support the ongoing development of CSLA .NET.

Make donation through PayPal - it's fast, free and secure!
Why donate?
Copyright (c) 2006-2010 Marimer LLC. All rights reserved.
Email admin@lhotka.net for support.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems