ObservableCollection subclass not serializing correctly in test unit (?)

321 views
Skip to first unread message

matt tagliaferri

unread,
Mar 8, 2012, 7:35:51 PM3/8/12
to servic...@googlegroups.com
ok, this might take a bit to explain.

I'm basing my services off of classes that use the CSLA library.  Not sure this is relevant, but I'll throw it out there.  The CSLA collection classes inherit (after a long chain of subclasses) to System.Collections.ObjectModel.ObservableCollection<T>.

I wrote a service to return one of these read-only collection classes.  Here is the outbound DTO:

 public class TeamsResponse {
        [DataMember]
        public Vid.Lib.MajorLeagueTeams Result { get; set; }   //CSLA class
        public ResponseStatus ResponseStatus { get; set; }
    }

And the service.

    public class TeamsService : ServiceBase<Teams>
    {
        protected override object Run(Teams request)
        {
            return new TeamsResponse { Result = Vid.Lib.MajorLeagueTeams.GetObject() };
        }
    }


This class returns data as expected when testing via the web page, so I know the CSLA class is working correctly.  However, when writing code for a unit test, the service returns null for both the ResponseStatus and the Result, with no error messages or exceptions.  My test unit looks something like this:

        [TestMethod]
        public void Can_I_Get_Teams()
        {

            var restClient = (IRestClient)new JsonServiceClient("http://localhost/vidsvc");
            restClient.Get<ServiceStack.ServiceInterface.Auth.AuthResponse>("/auth?username=xxx&password=yyy");
            var response = restClient.Get<TeamsResponse>("/teams");
            Assert.AreEqual(response.Result.Count, 30);
        }

In trying to figure out why the collection was not coming across correctly, I changed my outbound DTO to return a normal generic list.  This worked!

New Outbound DTO:

    [DataContract]
    public class TeamsResponse {
        [DataMember]
        public List<Vid.Lib.TeamInfo> Result { get; set; }
        public ResponseStatus ResponseStatus { get; set; }
    }

New Service

    public class TeamsService : ServiceBase<Teams>
    {
        protected override object Run(Teams request) {
           
            var tms = Vid.Lib.MajorLeagueTeams.GetObject();
            var lst =  new List<Vid.Lib.TeamInfo>();

            lst.AddRange(tms);
           
            return new TeamsResponse { Result =  lst };
        }
    }

Not totally sure why, but the ObservableCollection doesn't make it across the service in this unit test, unless I change the return result to a normal List<T>.






Demis Bellot

unread,
Mar 8, 2012, 7:50:29 PM3/8/12
to servic...@googlegroups.com
Basically it looks like ObservableCollection is not supported. 
ServiceStack.Text is a .NET 3.5 API and ObservableCollection is in .NET 4.0 - so there's no explicit support for it, although it should've worked via the normal routes (i.e.since it implements ICollection or IEnumerable) so something else is up trying to serialize the type.

IMO ObservableCollection has no business being inside DTO which should just be a structured, self-describing Data container with the sole purpose to hold your data - OCs seem like a UI concern, I recommend converting it to one in your clients that need it and not impact your services with it.

I recommend reducing the use of 'magic types' in DTOs - and realize this needs to be serialized into a wire-format and re-hydrated again. This is why shipping back db model entities is a broken concept and why we instead should be using Data Transfer Classes optimized for this purpose. 

- Demis

matt tagliaferri

unread,
Mar 8, 2012, 8:18:48 PM3/8/12
to servic...@googlegroups.com
I understand where you're coming from, except that the CSLA "magic types" provide a ton of functionality, especially when we start talking about read/write objects.  Things like centralized rules/validation, Dirty tracking, N-Level full object graph Undo (useful in Winforms/WPF world, not so much in web, obv), Oh, and all CSLA objects also happen to always be fully serializable, too (a requirement for the architecture).

It looks like I'll have to transfer the CSLA objects to thinner DTO-style objects in the service before sending it across the wire.  Not ideal, but I can live with it.  I guess that's what TranslateTo() is for...



On Thursday, March 8, 2012 7:50:29 PM UTC-5, mythz wrote:
Basically it looks like ObservableCollection is not supported. 
ServiceStack.Text is a .NET 3.5 API and ObservableCollection is in .NET 4.0 - so there's no explicit support for it, although it should've worked via the normal routes (i.e.since it implements ICollection or IEnumerable) so something else is up trying to serialize the type.

IMO ObservableCollection has no business being inside DTO which should just be a structured, self-describing Data container with the sole purpose to hold your data - OCs seem like a UI concern, I recommend converting it to one in your clients that need it and not impact your services with it.

I recommend reducing the use of 'magic types' in DTOs - and realize this needs to be serialized into a wire-format and re-hydrated again. This is why shipping back db model entities is a broken concept and why we instead should be using Data Transfer Classes optimized for this purpose. 

- Demis

Demis Bellot

unread,
Mar 8, 2012, 8:32:24 PM3/8/12
to servic...@googlegroups.com
CSLA objects also happen to always be fully serializable

On which serializers? the more esoteric types you use, the less chances it will work in all serializers

CSLA "magic types" provide a ton of functionality, especially when we start talking about read/write objects

I'm not suggesting you don't use it on your client, I'm suggesting you shouldn't use it in your DTOs, the workaround should hopefully be handed by 2 .ToList() / .ToObservable() extension methods.

Not ideal, but I can live with it.  I guess that's what TranslateTo() is for...

I'd imagine a TObservalble.ToList() will serve you better :)

Cheers,

matt tagliaferri

unread,
Mar 8, 2012, 8:32:41 PM3/8/12
to servic...@googlegroups.com
Some further information - it looks like the author of CSLA, Rocky Lhotka, has addressed the issue of using CSLA objects in the SOA world, and without getting too much into it - he agrees with you.  There are several ways for combining CSLA and a service-oriented architecture like ServiceStack, but none of them involve sending complex objects "across the boundary". 

Thanks for putting me on the correct path.

matt tagliaferri

unread,
Mar 8, 2012, 9:38:35 PM3/8/12
to servic...@googlegroups.com
CSLA supports serialization through either BinaryFormatter or NetDataContractSerializer.  For Silverlight environments, Rocky wrote his own serializer called the MobileFormatter.

MobileFormatter does have limitations.  It can serialize only primitive values, or objects that implement IMobileObject (that tell the MobileFormatter how to do its job)

(I didn't know these by heart, I had to look them up).

As for the quick .ToList() workaround - I have the issue that the object inside the CSLA collections are themselves CSLA objects (inheriting from BusinessBase or ReadonlyBase).  These objects carry much of the functionality I mentioned above (binding, undo, business rules, etc): stuff that would be considering extraneous in the SOA world.  So I would need to simplify those also.

I'm beginning to think my best bet is getting rid of the CSLA model behind the service layer, and instead using only Lightweight DTOs and either an ORM implementation to load (as you recommend), or some type of object collection factory method.

When dealing with user interfaces that do support CSLA - I can re-architecture these classes to load/save their data using the service layer.  So I get the benefit of not duplicating code and allowing the service layer to serve all my different architectures, but I get the benefit of CSLA classes in my older Winforms, WPF, Silverlight, and MVC apps, where binding and rule checking will be useful.  Pure HTML5/Javascript apps or reports could just hit the service layer directly.

Summing up - CSLA consumes the services, not the other way around.

My head hurts...
Reply all
Reply to author
Forward
0 new messages