Csla 3.5.1 Bug? NullReferenceException during Undo

Csla 3.5.1 Bug? NullReferenceException during Undo

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


rahulbpatel posted on Friday, September 12, 2008

I have the following classes:

Order (Root BO)
OrderItems (Child BLB)
OrderItem (Child BO)

I have added a type-level business rule in Order to make sure that there is at least one OrderItem in its (OrderItems) Items property:

protected override void AddBusinessRules()
{
  ValidationRules.AddRule<Order>(ItemsCountGreaterThanZero<Order>,   Order.ItemsProperty);
}


In order to trigger the rule check I have subscribed to the OrderItems.ListChanged event in Order:

private void AddHandlers()
{
      Items.ListChanged += new System.ComponentModel.ListChangedEventHandler(Items_ListChanged);
}


private void Items_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
{
  ValidationRules.CheckRules(Order.ItemsProperty);
}


I am getting a NullReference exception when I have removed an OrderItem from the (OrderItems) Items property and then call Order.CancelEdit()

This is basically what I'm seeing as I step thru the framework code:

  1. Through a series of undo method calls the Order._validationRules field is deserialized and restored.  However, because ValidationRules._target field is marked [NonSerialized()], Order._validationRules._target is null.
  2. Further along the undo process the child OrderItems undo methods are called.  During these calls an OrderItem that was deleted is restored back to the list.
  3. This triggers the OrderItems.ListChanged event and so the Order.Items_ListChanged event handler gets called
  4. The ValidationRules.CheckRules(Order.ItemsProperty) ultimately fails at line ValidationRules.cs:61 because _target is null:
    _typeRules = SharedValidationRules.GetManager(_target.GetType(), createObject);
I see that later on in the undo process, UndoChangesComplete() method is called, which calls ValidationRules.SetTarget(this) but this happens too late for the ListChanged event handler and this scenario.

Is this a bug or have I just set up my business objects incorrectly?  What would be the impact of calling the ValidationRules.SetTarget earlier?



RockfordLhotka replied on Friday, September 12, 2008

I'll add this to my list of things to investigate.

rob46 replied on Friday, October 17, 2008

Hi guys

I'm seeing the same issue in our application. We subscribe to a child collections ListChanged event so that we can call ValidationRules.CheckRules to invoke a validation rule on the parent. This rule is there to  ensure the child collection contains at least one item to be valid. In my scenario I have a unit test that calls BeginEdit on a parent collecion, adds a new parent object to the parent collection and then calls CancelEdit to reset it back to an empty collection. This simulates a user clicking the reset button in our UI. I see the same null reference exception in the ValidationRules class.

I agree that the problem seems to be that the _target field of the ValidationRules class is not referencing the undone business object before the Reset ListChanged event is raised.

You can workaround this issue by overriding the following methods on BusinsessBase to unsubsribe and subscribe to the event again when the undo operation is complete.

/// <summary>
/// Undoing the changes.
/// </summary>
protected override void UndoingChanges()
{
    base.UndoingChanges();
    DataSubjectTags.ListChanged -= DataSubjectTags_ListChanged;
}

/// <summary>
/// Undo operation completed.
/// </summary>
protected override void UndoChangesComplete()
{
    base.UndoChangesComplete();
    DataSubjectTags.ListChanged += DataSubjectTags_ListChanged;
}


What I'd really like to know is whether subscribing to a child collections ListChanged event to invoke validation rules on the parent business object is a safe and sensible design pattern? If it is then I guess this is probably a bug. If this isn't a good design pattern, do you have any better suggestions for child collection validation in the parent business object?

Would raising the reset ListChanged event in the UndoChangesComplete() method fix this? I guess it would be a bit unsafe as this method can be overridden and there is no guarentee the developer would call base.UndoChangesComplete()?

Anyway... loving the new features in CSLA 3.5.1 (believe it or not we have only just started to move from 1.0 to 3.5.1 - currently we have objects using both versions implemented side by side in our app!)

Thanks,
Rob

ajj3085 replied on Friday, October 17, 2008

If you're using 3.5 or higher, you can override OnChildChanged to run rules in the parent which contains the collection.  That seems to be working for me so far.

RockfordLhotka replied on Tuesday, November 18, 2008

This is a bug, and I've now fixed it in 3.6.

Copyright (c) Marimer LLC