CSLA 3.7 + VB Windows Forms Applications Serialization error

CSLA 3.7 + VB Windows Forms Applications Serialization error

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


jamie.clayton posted on Thursday, November 19, 2009

G'day all,

I've found a difficult problem in my Winforms application where I have recently upgraded from CSLA 3.0.3 (VB) to 3.7.0.0 (C#)

I've got a BO + ChildCollection of BO's. When I call the BO.Save method the CSLA.DataPortal.Update method now calls the Clone method and this fails (line 458).

I'm assuming it's trying to serialize the object graph (including the windows form that called the underlying code). Now Windows forms are not serializable, so the code fails with an error like.

Type 'myApp.GUI.frmMain' in Assembly 'MyApp, Version=2.29.3.18, Culture=neutral, PublicKeyToken=zxcvbnmasdfghjkl' is not marked as serializable.

It looks like Csla.Serialization.BinaryFormatterWrapper.Serialize raises an serialization error back up to the Update method, skipping the actual database update code. From what I can tell it's the following method that triggers the serialization exception.

public void Serialize(System.IO.Stream serializationStream, object graph)
{
_formatter.Serialize(serializationStream, graph);
}

Has anyone else experienced this behaviour? Is it a bug, or have I not configured something in v3.7.0.0?

JonnyBee replied on Thursday, November 19, 2009

Hi,

So what you are saying here is that your BO has a reference to the Windows Form?

I would recommend to have such dependencies. Your BO should not have references to the UI at all - only communicate through databinding and events. Only workaround is to make sure the Winform property is marked as both NotUndoable and NonSerializable.

jamie.clayton replied on Thursday, November 19, 2009

JonnyBee,

No the BO is definitely not referencing anything in the UI as it's in a separate project. I will hand check the code again, just in case.

The UI/BO code hasn't changed, just the CSLA framework. Previously, using the 3.0.3, the code worked. Now using the 3.7.0.0 edition I get this exception when I run the code. My conclusion is a bug in the CSLA or some missing implementation in my code.

ajj3085 replied on Thursday, November 19, 2009

Do you have any events?  A form listening to an event might be serialized as well... make sure you unhook all event handlers.

jamie.clayton replied on Thursday, November 19, 2009

Yes I have a progress event hooked up as the code loops throught a large amount of data and generates some "data cleanup tasks" which the BO saves to a database.

I really want the progress bar as the process is a very long one.

Jamie.

jamie.clayton replied on Thursday, November 19, 2009

Absolute LEGEND!

I had to change my progress event handling to use AddHandler and RemoveHandler, rather than a class level WithEvents variable declaration and then everything works as expected (or as I had when I referenced CSLA 3.0.3)

Thanks for identifying this issue. I doubt I could have found this as the cause of the problem. How did you know or learn about this?

Now I've just got to change lots more applications that I just migrated to 3.7 to use this event handling methodology. :)

jamie.clayton replied on Thursday, November 19, 2009

I've been thinking about this issue, because I spent 6 hours pulling my hair out debugging it.

If the CSLA was my code, I would be inclined to add some exception handling around this area to help me identify the problem in the future and speedup resolution for the less experienced developers on the team. I've had a couple of contractors get a little annoyed at some of the obfuscated exceptions that can occur when using the CSLA.

For instance, before cloning the object, checking the object for event handlers (if that's possible) and trapping serialization errors that might occur because of incorrectly configured UI's, then warning users about event handling configuration.

What does the community think of this approach and more importantly would Rocky mind doing this?

tmg4340 replied on Friday, November 20, 2009

I think you'll find that's a pretty tough thing to do.  The issue is that it wouldn't necessarily just be attached event handlers or other UI-related problems - you'd have to search the whole object graph for any non-serializable object reference.  That object graph could reach fairly far and wide.  You'd also have to deal with idiosyncracies surrounding all the different serialization techniques available, because each one works a little differently.

Presuming you could manage all these issues, the resulting code would be pretty ugly stuff, and also probably perform pretty poorly.

HTH

- Scott

ajj3085 replied on Friday, November 20, 2009

Also, this is a well-known issue which I think is discussed in the book, which is why Rocky's event add / remove code checks the delegate to see if its serializable or not, and keeps a seperate list of serializable / non-serializable delegates.

jamie.clayton replied on Sunday, November 22, 2009

Andy (ajj3085),

I've been working off CSLA 2005 book, so might have missed newer discussions on add/remove delegates.

The background on what I'm doing with progress bars is as follows.

I have a BO, Product, that updates some values in the database. I 'had' code in the BO.Save too loop through another BO.Collection, Orders and performed a calculation on each record which then call that Order.Save method. So the database got a hit as your looping through the collection. I thought the best place for this code was in the Business classes and use a progress event to let the user know what's going on (because it takes a few minutes).

However the nested classes with saves and progress events just doesn't work in CSLA 3.7, so I've change the code to expose the collection of records I want to review to the GUI and then loop through those and save each, updating the progress as you go a long. Effectively I've moved the code from one class method to the code behind the save button. Not the cleanest way I like to do things, but it works.

I did have some of this style of code on background worker tasks, which complicated things a little, but a little code re-organisation and it works.

RockfordLhotka replied on Sunday, November 22, 2009

I'd love to provide better help in this area, but the exception comes from the BinaryFormatter, not CSLA. In other words, it is a .NET exception, thrown by .NET, and there's nothing I can really do to change or improve it.

Well, I could - by entirely avoiding all the native .NET serialization - but that seems a bit extreme :)

jamie.clayton replied on Sunday, November 22, 2009

Rocky,

Thanks for the input. Scott (tmg4340) made some good points around object graphs as well.

I'm going to modify my application global error handler to check for the words serialization and then insert some further help for my developers to "check" for observer patterns (RaiseEvents) when working with CSLA BO's.

ajj3085 replied on Friday, November 20, 2009

Well, an event basically built in support for the observer pattern, which means when you hook events and you listen in one object (your Form, the observer) for events from another object (your BO, the observed), the observed has a reference to the observer.  Serializtion attempts to serialize the entire object graph, including other objects which your BO is referencing.  But the problem is Form is not serializable, hence your error.

I also have to ask what you're trying to do; it sounds like you have a progress bar that you want updated WHILE save is executing.  Is that correct?  If so, you're going about it the wrong way.  Search the forum, as this has been discussed before, but the solutions are not trival.

HTH

Andy

Copyright (c) Marimer LLC