multiple fetches possible?

multiple fetches possible?

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


mtrtm posted on Tuesday, September 18, 2012

Normal 0 false false false EN-US X-NONE X-NONE MicrosoftInternetExplorer4

Hi all,

I am working on a project using CSLA generated by codesmith and due to project considerations we will be re-generating quite often throughout the lifetime of the project.

Due to these considerations, I am running into a situation where I want to add my own fetch method in the business object but also want to keep the generated one.  I would just like to be able to give my custom written fetch a different name, or optionally add parameters to change the method signature (I am guessing that wouldn’t work due to serialization concerns), just so I can call multiple implementations of fetch.

It seems like having multiple implementations of fetch side by side should be something easy to do but I can’t find anything on it.  Does anyone have any feedback on this?

Just to point out: I do understand you can have multiple implementations of fetch all with different criteria, but in most of the scenarios we are going to be handling I don’t need/want different criteria and feel that creating another class just to get a different method signature seems like a very undesirable way to make a method call.

JonnyBee replied on Tuesday, September 18, 2012

Why do you need different inplementation of Fetch? UnitTesting/IntegrationTests? 

Simplest way is to use DataPortal_Fetch(object criteria) and 

so that your DataPortal_Fetch will know how to handle fetch.

For unit tests/integration tests you could also opt for Repository pattern and inject
the actual data access implementation with an IOC container. 

mtrtm replied on Tuesday, September 18, 2012

Hi Jonny, thanks for the reply.  I don't want multiple fetch methods for unit testing.  I want a custom alternative fetch, similar to how many api's have overloaded method signatures and/or methods named very similarly, and, while they may have the same return type they are used in different circumstances.

Is there no way to implement multiple fetches?

JonnyBee replied on Tuesday, September 18, 2012

My recommendation is to use different Criteria objects. 

mtrtm replied on Wednesday, September 19, 2012

Hi Jonny,

Thanks again for the reply.  I went to add some parameters to the criteria, and if I add a List<String> I get a serialization exception.  Same if I try to add an object, string array etc.  Any ideas on why that may be?  Here is the error:

System.Runtime.Serialization.SerializationException: Type 'System.String[]' with data contract name 'ArrayOfstring:http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at WriteSerializationInfo.FieldDataToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
   at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at WriteKeyValueOfstringSerializationInfo.FieldDataOzoZvLrmToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
   at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at WriteArrayOfKeyValueOfstringSerializationInfo.FieldDataOzoZvLrmToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract )
   at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at WriteSerializationInfoToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
   at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at WriteArrayOfSerializationInfoToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , CollectionDataContract )
   at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
   at Csla.Serialization.Mobile.CslaXmlBinaryWriter.Write(Stream serializationStream, List`1 objectData)
   at Csla.Serialization.Mobile.MobileFormatter.Serialize(Stream serializationStream, Object graph)
   at Csla.Serialization.Mobile.MobileFormatter.Serialize(Object obj)
   at Csla.DataPortalClient.WcfProxy`1.BeginFetch(Object criteria, Object userState)
   at Csla.DataPortalClient.WcfProxy`1.BeginFetch(Object criteria)
   at Csla.DataPortal`1.BeginFetch(Object criteria)

edore replied on Wednesday, September 19, 2012

Hi!

I strongly suggest using the "Search this site" textbox at the right hand corner of the forum.  As a matter of fact, you're not the first one to have a problèm with serialization.  And moreover, buy Rocky's e-books and read them, they will answer 90% of your questions about basic CSLA usage, you won't regret it!

mtrtm replied on Wednesday, September 19, 2012

OK, so I may do a separate post on this since this question has changed a bit, but any help would be much appreciated since right now I am stumped.

Edore - yes, I have heard of google and site searches and have the books and have spent quite a bit of time on this issue. If you know something I don't feel free to help.

I figured out by hooking up the CSLA source (4.3.1) that CslaReaderWriterFactory.GetDataContractSerializer adds 4 hardcoded known types into the serializer, allowing WCF to serialize List<int>, byte[], DateTimeOffset and char[] (in addition to primitive types).

So if I am understanding this correctly then CSLA can't serialize anything else other than primitives and those 4 types!? I could add more types to the source and recompile, which I may just do but that seems like the wrong way to do things. Just to test I added string[] and my error went away.

I find it hard to believe that what I am understanding is true - can anyone tell me what I am missing? Can you really not use anything other than primitives and the 4 hardcoded types in Criteria objects? I see some web posts about complex criteria and the book even has one, though it uses List<int> (one of the hardcoded KnownTypes) and not List<string>.

mtrtm replied on Wednesday, September 19, 2012

Is this problem due to the fact we haven't gotten around to subclassing the WcfProxy?  I just remembered the DataPortal book says you should write your own data portal channel for silverlight.

JonnyBee replied on Thursday, September 20, 2012

You should use the lists that CSLA offers. The simplest one is MobileList. 

edore replied on Thursday, September 20, 2012

To make it short, the MobileFormatter must already know how to serialize types (which it does for basic types, but List<T> is not one of them).  Otherwise, the object must "participate" in the serialization process, as Rocky said in some posts.  For the object to participate, you must override some methods on your BO.  In the following example I serialize a private backing field :

        protected override void OnGetChildren(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)
        {
            base.OnGetChildren(info, formatter);        
            Serialize(info, formatter, _officeDepartment, OfficeDepartmentPropertyName);  
        }
 
        protected override void OnSetChildren(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)
        {
            OfficeDepartment = Deserialize<OfficeDepartment>(info, formatter, OfficeDepartmentPropertyName);
            base.OnSetChildren(info, formatter);
        }
 
where Serialize and Deserialize are implemented as follows, in my own BusinessBase sub-class :
 
        protected T Deserialize<T>(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter, string propertyName)
            where T : class
        {
            if (info.Children.ContainsKey(propertyName))
            {
                var data = info.Children[propertyName];
                return (T)formatter.GetObject(data.ReferenceId);
            }
            return null;
        }
 
        protected T Serialize<T>(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter, T currentValue, string propertyName)
            where T : class
        {
            if (currentValue != null)
            {
                var fieldManager = formatter.SerializeObject(currentValue);
                info.AddChild(propertyName, fieldManager.ReferenceId);
            }  
            return null;
        }

edore replied on Thursday, September 20, 2012

You can also declare your property as MobileList<string> as Jonny states, the BO will know how to take care of serialization.

Copyright (c) Marimer LLC