"Index was outside the bounds of the array." error with CSLA 3.5 Beta 1

"Index was outside the bounds of the array." error with CSLA 3.5 Beta 1

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


triplea posted on Sunday, March 16, 2008

I finally got to play with the latest release (cslacs-3.5.0-080222.zip is the file I've got). It looks great but I stumbled upon my first problem.
I have an editable root object (Customer) which has contains an editable child object (Address). Using a Linq DAL, I fetch the Customer fields fine but when I get to the fetch part of my Address object, the first line that tries to populate a property like this:

LoadProperty<string>(HouseNumberProperty, address.HouseNumber);

fails with the following error: "Index was outside the bounds of the array." which gets caught in protected void LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue) and because in PropertyInfo.Index the index is -1. Now I checked another (very long) thread where a similar issue was reported but it seemed it happened for more complex scenarios. Mine is a straightforward one (I think).
Apologies but I am a bit new to .Net 3.5 in general so might be doing something obviously silly here...

skagen00 replied on Sunday, March 16, 2008

What does your property declaration look like?

And is your class just a concrete class with no registered properties declared in any parent classes?

RockfordLhotka replied on Monday, March 17, 2008

This problem is most likely caused by a bug in your RegisterProperty() call for this property. The most common issue is not getting the containing type parameter set correctly, so the property is registered with the wrong business object type.

skagen00 replied on Monday, March 17, 2008

One of the common errors the team here makes is to leave off the "static" part of the declaration for the property, so you might look at that too.

triplea replied on Monday, March 17, 2008

Thanks to both. I was indeed using the wrong containing type parameter so I changed it and it works fine. I now begin to understand how this can be an issue with inheritance... I havent tried it yet but was there any final solution from the previous very big thread? I know its not best practice but in a lot of occasions I have something like:

Customer : BusinessBase<Customer>
GoodCustomer : Customer
BadCustomer : Customer

And use Customer to bind on a view that allows editing customers but doesnt (and shouldnt) care about the quality of the customer. That would mean that all the properties are defined in Customer but usually the validation/authorization rules are set in the conrete extended classes. Should I still register the properties in Customer with type Customer or is there a catch?

RockfordLhotka replied on Monday, March 17, 2008

You can register your properties in a base class – against the base class type. That works fine.

 

The issue with inheritance is that .NET won’t necessarily initialize the static fields in your base class early enough in the process, so you need to put code in your constructor on OnDeserialized() method to set a static field (such as an integer field named _dummy or something). That forces static fields to initialize in that class and all is well.

 

Rocky

triplea replied on Monday, March 17, 2008

Thanks, I will convert some such existing cases and see how that goes.

RockfordLhotka replied on Monday, March 17, 2008

That would be very helpful - please let me know how it goes - thanks!

van replied on Tuesday, September 30, 2008

I have a problem with LoadProperty in base class (CSLA 3.5 and 3.5.1 version). I have something like this:

public abstract class BaseObject<T> : BusinessBase<T>

public abstract class BaseNameDescriptionBusinessObject<T> : BaseObject<T> where T : BaseNameDescriptionBusinessObject<T>

public class Funkcija : BaseNameDescriptionBusinessObject<Funkcija>

and exception 'Property load or set failed for property Naziv (One or more properties are not registered for this type)' appeare in BaseNameDescriptionBusinessObject<T> class when use LoadProperty<string>(NazivProperty, reader.GetString("Naziv")); I try with dummy in constructor but it didn't help.

RockfordLhotka replied on Tuesday, September 30, 2008

Do you also set the static/Shared _dummy field in an override of OnDeserialized()?


 
----- Original Message -----
From: van
To: "rocky@lhotka.net"
Subject: Re: [CSLA .NET] "Index was outside the bounds of the array." error with CSLA 3.5 Beta 1
Date: Tue, 30 Sep 2008 07:07:31 -0500

I have a problem with LoadProperty in base class. I have like something this:

public abstract class BaseObject<T> : BusinessBase<T>

public abstract class BaseNameDescriptionBusinessObject<T> : BaseObject<T> where T : BaseNameDescriptionBusinessObject<T>

public class Funkcija : BaseNameDescriptionBusinessObject<Funkcija>

and exception 'Property load or set failed for property Naziv (One or more properties are not registered for this type)' appeare in BaseNameDescriptionBusinessObject<T> class when use LoadProperty<string>(NazivProperty, reader.GetString("Naziv")); I try with dummy in constructor but it didn't help.





van replied on Wednesday, October 01, 2008

I try with an override of OnDeserialized() now, but it doesn't solve the problem.

Maybe I have a some bug in my classes and there is a code:

// BaseObject<T> class

[Serializable]

public abstract class BaseObject<T> : BusinessBase<T>, IBusinessObjectId where T : BaseObject<T>

{

#region Constructor

protected BaseObject()

{

LoadProperty<Guid>(UidProperty, Guid.Empty);

}

#endregion

#region FactoryMethods

public static T CreateObject()

{

return DataPortal.Create<BaseObject<T>>() as T;

}

#endregion

#region DataAccess

[RunLocal()]

protected override void DataPortal_Create()

{

Uid = Guid.NewGuid();

}

#endregion

#region Properties

private static PropertyInfo<Guid> UidProperty = RegisterProperty<Guid>(typeof(T), new PropertyInfo<Guid>("Uid", "Uid"));

public Guid Uid

{

get { return GetProperty<Guid>(UidProperty); }

set { SetProperty<Guid>(UidProperty, value); }

}

public bool IsNull

{

get

{

return Uid.Equals(Guid.Empty);

}

}

#endregion

#region Methods

protected void DataFetch(NullableDataReader reader)

{

try

{

if (reader.Read())

{

LoadData(reader);

}

}

catch (Exception ex)

{

throw;

}

finally

{

if (!reader.IsClosed)

{

reader.Close();

}

}

}

protected virtual void LoadData(NullableDataReader reader)

{

try

{

LoadProperty<Guid>(UidProperty, reader.GetGuid("Uid"));

}

catch (Exception ex)

{

throw;

}

}

protected virtual void LogicalDelete(string tableName)

{

try

{

Database db = DatabaseFactory.CreateDatabase();

DbCommand cmd = db.GetStoredProcCommand("usp_LogicalDelete");

db.AddInParameter(cmd, "@tableName", DbType.String, tableName);

db.AddInParameter(cmd, "@uid", DbType.Guid, Uid);

db.ExecuteNonQuery(cmd);

}

catch (Exception ex)

{

LogHelper.LogException(ex);

throw;

}

}

#endregion

}

 

// BaseNameDescriptionBusinessObject<T>

[Serializable]

public abstract class BaseNameDescriptionBusinessObject<T> : BaseObject<T> where T : BaseNameDescriptionBusinessObject<T>

{

#region members

private static int _dummy;

#endregion

#region Constuctor

protected BaseNameDescriptionBusinessObject()

{

_dummy = 10;

}

#endregion

#region ValidationRules

protected override void AddBusinessRules()

{

AddCustomRules();

}

private void AddCustomRules()

{

ValidationRules.AddRule<T>(NazivPostoji, "Naziv");

}

private static bool NazivPostoji<T>(T target, Csla.Validation.RuleArgs e) where T : BaseNameDescriptionBusinessObject<T>

{

if (string.IsNullOrEmpty(target.Naziv))

{

e.Description = "Unesite naziv.";

return false;

}

return true;

}

#endregion

#region Property

//private static PropertyInfo<string> NazivProperty = RegisterProperty<string>(typeof(T), new PropertyInfo<string>("Naziv", "Naziv"));

//private string _naziv;

//public string Naziv

//{

// get { return GetProperty<string>(NazivProperty, _naziv); }

// set { SetProperty<string>(NazivProperty, ref _naziv, value); }

//}

//private static PropertyInfo<string> OpisProperty = RegisterProperty<string>(typeof(T), new PropertyInfo<string>("Opis", "Opis"));

//private string _opis;

//public string Opis

//{

// get { return GetProperty<string>(OpisProperty, _opis); }

// set { SetProperty<string>(OpisProperty, ref _opis, value); }

//}

private static PropertyInfo<string> NazivProperty = RegisterProperty<string>(typeof(T), new PropertyInfo<string>("Naziv", "Naziv"));

public string Naziv

{

get { return GetProperty<string>(NazivProperty); }

set { SetProperty<string>(NazivProperty, value); }

}

private static PropertyInfo<string> OpisProperty = RegisterProperty<string>(typeof(T), new PropertyInfo<string>("Opis", "Opis"));

public string Opis

{

get { return GetProperty<string>(OpisProperty); }

set { SetProperty<string>(OpisProperty, value); }

}

 

#endregion

#region Methods

protected override void LoadData(NullableDataReader reader)

{

try

{

base.LoadData(reader);

LoadProperty<string>(NazivProperty, reader.GetString("Naziv"));

LoadProperty<string>(OpisProperty, reader.GetString("Opis"));

//_naziv = reader.GetString("Naziv");

//_opis = reader.GetNullableString("Opis");

}

catch (Exception ex)

{

LogHelper.LogException(ex);

throw;

}

}

protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)

{

_dummy = 20;

base.OnDeserialized(context);

}

#endregion

}

 

// Funkcija

[Serializable]

public class Funkcija : BaseNameDescriptionBusinessObject<Funkcija>

{

#region Constructors

private Funkcija()

{

}

#endregion

#region FactoryMethods

public static Funkcija CreateChildObject()

{

return DataPortal.CreateChild<Funkcija>();

}

public static Funkcija GetFuinkcijaByUid(Guid uid)

{

return DataPortal.Fetch<Funkcija>(new SingleCriteria<Funkcija, Guid>(uid));

}

public static Funkcija GetChildByReader(NullableDataReader reader)

{

return DataPortal.FetchChild<Funkcija>(new SingleCriteria<Funkcija, NullableDataReader>(reader));

}

#endregion

#region DataAccess

private void Child_Fetch(SingleCriteria<Funkcija, NullableDataReader> criteria)

{

try

{

LoadData(criteria.Value);

}

catch (Exception ex)

{

LogHelper.LogException(ex);

throw;

}

}

private void DataPortal_Fetch(SingleCriteria<Funkcija, Guid> criteria)

{

try

{

Database db = DatabaseFactory.CreateDatabase();

DbCommand cmd = db.GetStoredProcCommand("usp_GetFuncijaByUid");

db.AddInParameter(cmd, "@uid", DbType.Guid, criteria.Value);

using (NullableDataReader reader = new NullableDataReader(db.ExecuteReader(cmd)))

{

DataFetch(reader);

}

}

catch (Exception ex)

{

throw;

}

}

protected override void Child_Create()

{

Uid = Guid.NewGuid();

ValidationRules.CheckRules();

}

private void Child_Insert()

{

DoSave();

}

private void DoSave()

{

try

{

Database db = DatabaseFactory.CreateDatabase();

DbCommand cmd = db.GetStoredProcCommand("usp_FunkcijaInsertUpdate");

db.AddInParameter(cmd, "@uid", DbType.Guid, Uid);

db.AddInParameter(cmd, "@naziv", DbType.String, Naziv);

db.AddInParameter(cmd, "@opis", DbType.String, Opis);

db.AddInParameter(cmd, "@isNew", DbType.Boolean, IsNew);

db.ExecuteNonQuery(cmd);

}

catch (Exception ex)

{

LogHelper.LogException(ex);

throw;

}

}

private void Child_Update()

{

DoSave();

}

private void Child_DeleteSelf()

{

LogicalDelete("Funkcije");

}

#endregion

}

 

Is there I'm doing something wrong?

stefan replied on Wednesday, October 01, 2008

Hi van,

van:

// BaseObject<T> class

[Serializable]

public abstract class BaseObject<T> : BusinessBase<T>, IBusinessObjectId where T : BaseObject<T>

{

#region Constructor

protected BaseObject()

{

LoadProperty<Guid>(UidProperty, Guid.Empty);

}

#endregion

...

Is there I doing something wrong?


Yes! Look at your constructor - missing something thereWink [;)]

Read this:  http://forums.lhotka.net/forums/post/26436.aspx


Stefan

van replied on Thursday, October 02, 2008

I added static field and an override of OnDeserialized() and I now have:

// BaseObject class

private static int _forceInit;

#region Constructor

protected BaseObject()

{

_forceInit = 5;

LoadProperty<Guid>(UidProperty, Guid.Empty);

}

protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)

{

_forceInit = 10;

}

 

// BaseNameDescriptionBusinessObject class

private static int _dummy;

#region Constuctor

protected BaseNameDescriptionBusinessObject()

{

_dummy = 10;

}

protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)

{

_dummy = 20;

}

 

//  Funkcija class

private static int _forceInit;

#region Constructors

private Funkcija()

{

_forceInit = 10;

}

protected override void OnDeserialized(System.Runtime.Serialization.StreamingContext context)

{

_forceInit = 15;

}

 

and problem still exist. Properties in the BaseObject and Funkcija classes registered properly and there is not a problem, but property Naziv and Opis in the BaseNameDescriptionBusinessObject never registered. When I go through debug, lines

private static PropertyInfo<string> NazivProperty = RegisterProperty<string>(typeof(T), new PropertyInfo<string>("Naziv", "Naziv"));

and

private static PropertyInfo<string> OpisProperty = RegisterProperty<string>(typeof(T), new PropertyInfo<string>("Opis", "Opis"));

executed before

protected override void LoadData(NullableDataReader reader)

{

try

{

base.LoadData(reader);

LoadProperty<string>(NazivProperty, reader.GetString("Naziv"));

LoadProperty<string>(OpisProperty, reader.GetString("Opis"));

//_naziv = reader.GetString("Naziv");

//_opis = reader.GetNullableString("Opis");

}

catch (Exception ex)

{

LogHelper.LogException(ex);

throw;

}

}

 

but it's throw an exception 'Property load or set failed for property Naziv (One or more properties are not registered for this type)'

RockfordLhotka replied on Thursday, October 02, 2008

The _forceInit code looks right. You have it in EVERY class? Base and sub?

 

Rocky

van replied on Friday, October 03, 2008

Yes, I know but stefan wrote that I missing something in BaseObject class. He meaned that I haven't _forceInit in this class. I readed your post at link  http://forums.lhotka.net/forums/post/26436.aspx and I know that it is not need in BaseObject class, because inherited directly from BusinessBase<T>, but I try _forceInit in every class. Is it mean that my classes in second post are good and changes don't need? There is a _dummy only in BaseNameDescriptionBusinessObject.

RockfordLhotka replied on Friday, October 03, 2008

I’ll try to be as clear as I can.

There are exactly two scenarios.

1.       Your business class inherits directly from a CSLA base class.

In this case you don’t need to do anything special, your code should just work.

2.       Your business class inherits from a custom base class that inherits from a CSLA base class. This scenario can go n levels deep.

In this case you must include the _forceInit code in EVERY ONE OF YOUR CLASSES in that inheritance hierarchy.

If you are using code-gen, I’d just put it in the template and always include the _forceInit code. It doesn’t cause harm, and would simplify template creation.

 

van replied on Saturday, October 04, 2008

Thank you Rocky, thank you stefan. I try with complete new solution and it's work fine. Smile [:)]

Jack replied on Tuesday, February 03, 2009

I am getting this error in 3.6.1 (with _forceInit removed everywhere).

Any call in the overridden OnDeserialized event to a managed property blows up:

Index was outside the bounds of the array.

   at Csla.Core.FieldManager.FieldDataManager.GetFieldData(IPropertyInfo prop) in C:\Csla\Framework\cslacs\Csla\Core\FieldManager\FieldDataManager.cs:line 142

Is that not the correct place to rebuild references and re-initialize 3rd party controls that don't support serialization?

I can get around the issue in my UI by calling GetBO, and then calling the ReLink method that I had referenced in my OnDeserialized. 

I'm using a WCFProxy.

Thanks

jack

RockfordLhotka replied on Tuesday, February 03, 2009

Are you calling base.OnDeserialized()? And are you calling it before your code runs?

 

I haven’t looked into the code, but if I remember correctly, some work occurs in some of the CSLA base classes that is rather critical.

 

Rocky

Jack replied on Wednesday, February 04, 2009

RockfordLhotka:

Are you calling base.OnDeserialized()? And are you calling it before your code runs?

 

I haven’t looked into the code, but if I remember correctly, some work occurs in some of the CSLA base classes that is rather critical.

 

Rocky



Beautiful - worked like a charm.  Calling the Base.OnDeserialized() first is required.  Nice way to start the morning :-)

Thank you

RockfordLhotka replied on Wednesday, February 04, 2009

This, by the way, is a perfect example of why inheritance is a tightly coupled relationship, and why (in general) it is best to favor composition over inheritance.

 

When you override a method you don’t explicitly know whether you should or shouldn’t call the base method – and if you do, you don’t know if you need to call it first, last or in the middle.

 

That’s a serious weakness of the whole inheritance idea.

 

Rocky

 

ajj3085 replied on Wednesday, February 04, 2009

I've handled this problem... maybe Csla can offer something similar.  Of course I know the problem... everyone will want a different hook at some different point in the process.. Big Smile [:D]

[OnDeserialized]
private void
OnDeserialized( StreamingContext context ) {
       OnDeserializing( context );

       // normal Csla OnDeserialized

      OnDeserlizeComplete( context );
}

protected virtual OnDeserializing( StreamingContext context ) { }
protected virtual OnDeserializeComplete( StreamingContext context ) { }

I've done this in my own code, when I absolutely want the base class behavior to run no matter what the subclass does, but still give the subclass different points in the process to hook into.

Just something to consider.. it seems to provide a little decoupling, in that you can't screw up what the base class needs to do.

Andy

RockfordLhotka replied on Wednesday, February 04, 2009

That's a possible solution Andy, but only if there's behavior in just one level of the base class structure.

If there's behavior in multiple base class levels (which may be the case in CSLA), then you'd have two protected virtual methods - which leads to confusion over which to override.

Witness the confusion over the ChildChanged event methods (there were two - one with "Internal" in the name) and it confused the heck out of several people. So one of the first changes to 3.6 was to eliminate the "Internal" method so now there's just one.

So you are right - in a simple case that's a good answer. But in the general case it is still an issue.

ajj3085 replied on Wednesday, February 04, 2009

Yes, I realize it's not an ideal solution by any stretch, which is why I didn't post it yesterday when I discovered my issue.Smile [:)]

At the very least though if this were done the "missing behaviors" would always be behaviors users of the of the Csla framework coded themselves... not something unexpected like the ValidationRules being empty (and even that depending on how Csla was configured) as opposed to some rules were there and others were not. 

I guess this is a matter of what is more confusing.  Smile [:)]

vbbeta replied on Wednesday, August 04, 2010

Hey rocky this thread was very helpfull for me

 

thanks a million i like when you reply onquestions its a big help...

CODE WELL

Copyright (c) Marimer LLC