1

I have some POCO objects that are set up for use with Entity Framework Code First.

I want to return one of those objects from an ApiController in my ASP.NET MVC 4 website, and then consume it in a client application.

I originally had problems with the serialization of the object at the server end, because the Entity Framework was getting in the way (see Can an ApiController return an object with a collection of other objects?), and it was trying to serialize the EF proxy objects rather than the plain POCO objects. So, I turned off proxy generation in my DbContext to avoid this - and now my serialized objects look OK (to my eye).

The objects in question are "tags" - here's my POCO class:

public class Tag
{
    public int Id { get; set; }

    public int ClientId { get; set; }
    public virtual Client Client { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public bool IsActive { get; set; }
}

Pretty standard stuff, but note the ClientId and Client members. Those are EF Code First "navigation" properties. (Every tag belongs to exactly one client).

Here's what I get from my ApiController:

<Tag xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Foo">
  <Client i:nil="true"/>
  <ClientId>1</ClientId>
  <Id>1</Id>
  <IsActive>true</IsActive>
  <Name>Example</Name>
</Tag>

The Client member is nil because having disabled proxy generation I don't get automatic loading of the referenced objects. Which is fine, in this case - I don't need that data at the client end.

So now I'm trying to de-serialize those objects at the client end. I had hoped that I would be able to re-use the same POCO classes in the client application, rather than create new classes. DRY and all that. So, I'm trying:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(Tag));

var tag = xmlSerializer.Deserialize(stream);

But I've run into two problems, both of which are due to EF Code First conventions:

Problem 1: Because my Tag class has a Client member, the XmlSerializer is complaining that it doesn't know how to de-serialize that. I guess that's fair enough (though I had hoped that because the member was Nil in the XML it wouldn't care). I could pass in extra types in the XmlSerializer constructor, when I tried that, it then complained about other classes that Client uses. Since Client references all sorts of other objects, I'd end up having to pass in them all!

I tried using the [DataContract] and [DataMember] attributes to remove the Client member from the XML (by not marking it as a DataMember). That did remove it from the XML, but didn't stop the XmlSerializer from whining about it. So I guess it's not the fact that it's in the XML that's the problem, but that it's in the class definition.

Problem 2: When I did try passing in typeof(Client) as an extra type, it also complained that it couldn't de-serialize that class because it contains an interface member. That's because - again due to EF Code First conventions - it has a Tags member as follows:

`public virtual ICollection<Tag> Tags { get; set; }`

So it looks like even if I get over the referenced-types problem, I'm still not going to be able to use my POCO classes.

Is there a solution to this, or do I have to create new DTO classes purely for use at the client side, and return those from my ApiController?

Community
  • 1
  • 1
Gary McGill
  • 26,400
  • 25
  • 118
  • 202

1 Answers1

0

I just tried using DataContractSerializer instead of XmlSerializer, and for the Tag class that seems to work. I've yet to try it with a class that has a virtual ICollection<T> member...

Update: tried it, and it "works". It still manages to reconstruct the object, and leaves the ICollection member at null.

Update 2: OK, that turned out to be a dead end. Yes, it meant that I could correctly serialize and de-serialize the classes, but as everyone kept telling me, DTO classes were a better way to go. (DTO = Data Transfer Objects - classes created specifically for transferring the data across the wire, probably with a subset of the fields of the original).

I'm now using AutoMapper (thanks Cuong Le) so that I can easily transform my POCO entities into simpler DTO classes for serialization, and that's what I'd recommend to anyone faced with the same problem.

Gary McGill
  • 26,400
  • 25
  • 118
  • 202