I have been working with CSLA 3.7 for a couple of years now. During that time, I refactored how we were using the criteria object from each business object using its own to all using a single custom criteria object. My version basically wrapps a SQLCommand object and simplifies the DataPortal_Fetch routine to just provide a connection and execute. This reduced code complexity and about 50k lines of code from our solution -- made me happy.
Recently, we began upgrading to CSLA 4 and started using CodeSmith. Of course, out of the box, CodeSmith generates a criteria per BO. I redid the template and volia, I am generating my version of a custom criteria object. I accomplished this by creating a few objects like I wanted them and then modified the templates to produce that exact code.
Once I was generating code, I put a simple UI on top of my mini-library to watch it work. Actually, I had added the UI earlier, but it only retrieved an Editable Root just to see it work -- baby steps. My test consists of an Editable Root, an Editable Child List and the Editable Child Objects. Plus an ExistsCommand object and my custom criteria.
First baby step is to put text from my EditableRoot into my text box. YEAH, it worked perfectly. Next, I bind the EditableChildList to my DataSource property of my UltraGrid. BAM! I get "Type 'System.Data.SqlClient.SqlCommand' in Assembly 'System.Data' is not marked as serializable". WHAT?
I dig some and see others having similar "not marked as" errors, but none are exactly what I am running into. I trace it to the ExistsCommand Shared Method "Execute". It is the DataPortal.Execute(cmd) line. If I comment out this line and just return "true" then my grid populates perfectly.
Just to be certain, I completely rewrote my criteria object. I took out all of my SQL wrappings and just used primitives. I then created my SQLCommand object and supporting SqlClient items inside the DataPortal_Fetch function. I get the same error in the same location. So it does not seem to be directly related to the SQLCommand in my CustomCriteria object or it would have started working when I removed all SQL references from the CustomCriteria object.
I am sure it has to do with my CustomCriteria implementation; however I don't really get it. In my first working implementation of my CustomCriteeria object, using CSLA 3.7, all of our New() constructors had "MyBase.New(GetType(T))" in them to ensure we provided our type. That MyBase.New(Type) is no longer supported. I suspect my issue is somehow related to this change, but I do not know how to fix it. However, I also have doubts as it is complaining about SqlCommand.
Has anyone else experienced this? I am pretty much LOST at this point.
Thanks in advance for your assistance.
I'm adding additional information to anyone else who may be looking at this. We had a discussion on this here and here. As a suggestion, what if you create a new criteria object or try passing in a built in CSLA criteria object to the Exists Command? Does this make any difference.
I tried the "new criteria" when I rewrote mine to not include SQLCommand and just have a dictionary. Thus the error about SQLCommand is not marked as serializable is not due to any SQLCommand in my criteria object. If it were specific to my criteria objects SQLCommand, then my removing it would have also removed the error.
And, I just did a quick project using the Entites.cs project and added the same BusinessObjects and it works fine.
I very much suspect it is something with the ExistsCommand and my CustomCriteria objects relationships; however I cannot seem to find the issue. I feel it has to do with typing the criteria object for each use.
My CustomCriteria object is defined thus:
Public Class CustomCriteria(Of T)
Inherits Csla.CriteriaBase(Of CustomCriteria(Of T))
Private _cmd as SqlCommand
Private _stateBag as New Dictionary(Of String, Object) ' I had this implemented prior to CSLA 4 coming out; just named differently. Named it here to make it recognizable
Public Property Command() As SqlCommand ' typical property set/get for _cmd. Not typing it all out here
Public Sub New()
MyBase.New() ' This used to have a GetType(T) parameter passed to MyBase.New; CSLA 4 removed that parameter for some reason
_cmd = New SqlCommand()
' 4 other constructors that mimic the SqlCommand constructors and setup the SqlCommand object appropriately
' The two readonly properties as defined by IGeneratedCriteria;
' A method for setting up the stateBag. Since we are not using the constructor for stateBag operations, I have this setter for adding properties
Public Sub SetProperty(Byval PropertyName as String, ByVal PropertyValue as Object)
If Not _stateBag.ContainsKey(PropertyName) Then _stateBag.Add(PropertyName, PropertyValue)
That is pretty much my custom criteria class as I want it defined. Some tweaking will be required with the SetProperty perhaps; however, the only thing I use the stateBag for is DataPortal_Create. Anything executing a stored procedure or SQL is done via the Constructors.
This has worked really well for us in our implementation in the past (CSLA 3.7). I am a little confused as to why it doesn't work any longer (CSLA 4). The SqlCommand is not marked as serializable is an odd error since it works on DataPortal_Fetch but not in ExistsCommand. Further confused as to why it keeps failing when all SqlCommand is removed from my custom criteria for a test; other than there is another SqlCommand that is causing the failure.
Hope this helps describe it more.
As an update: If I add <nonserialized()> to the Private _cmd as SqlCommand, then the code works; however, this is baffling since when I remove all SqlCommand references and just use "StateBag" implementation, I still get a not marked as Serializable error for a SqlCommand object. I will move on with the attribute addition; however my OCD nature is having a difficult time with this since no command object in my criteria continues to fail. What would I add <nonserialized()> to in that circumstance?
Ah well, am sure my mind will let it go eventually, but for now, it causes my head to hurt! :)
That is really odd... My mind must be going because I could have swore that specific modifiers were not serialized like a private members or properties. But according to this very old document, says that they will be . I would recommend to never attempt to serialize anything like a SqlCommand or any of the Sql classes over the wire (just asking for trouble). I'd recommend taking a look at a best practices or guidelines document on serialization as it really helps when working with serialization. We all could use a brush up from time to time as we all can forget if we don't use it everyday, myself included.
When it comes to this working in CSLA 3.7 vs 4.0. That could be a number of things like the CLR (.NET 3.5 vs 4.0) or hypothetically speaking if CSLA was using Xml Serialization and it was changed to Binary Serialization etc... Without investigating it could be a few things.
Copyright (c) Marimer LLC