Grandizer
Grandizer

Reputation: 3025

How to fix a Circular Reference Issue with WCF

I have a normalized set of tables. Owner, Dog, License (those are the major ones) Every Owner can have multiple Dogs and every Dog can have multiple Licenses. There are a few reference tables associated to each of those objects like Address for the Owner, Breed and Color for the Dog and LicenseType for the License. I do not believe those are my issue.

This is essentialy Code First (using the Reverse Engineer Code First tool) so I have no EDMX. I am having a circular reference issue and it is killing me. All of the articles I read say just to put the IsReference = true attribute on. This is great if it is only a Parent-Child releationship. I have a Grandparent-Parent-Child relationship. I have tried this article with no luck. I see so many articles out there but most of them are 4+ years old. I want what should be done and works in .Net 4 (not 4.5) I can't be the only one out there with this situation. My brain is mush at this point.

Here is my code that grabs the object from the database. It works like a champ.

using (DogLicensingContext db = new DogLicensingContext()) {
    Result = (from l in db.Licenses
        .Include(x => x.Dog) // Get the Dog on this License
        .Include(x => x.Dog.Owner)
        .Include(x => x.Dog.Owner.Title)
        .Include(x => x.Dog.Owner.Dogs) // Gets me all of their Dogs
        .Include(x => x.Dog.Owner.Dogs.Select(d => d.Licenses))
        .Include(x => x.Dog.Owner.Dogs.Select(d => d.Licenses.Select(l => l.TagStyle)))
        .Include(x => x.Dog.Owner.Dogs.Select(d => d.Breed))
        .Include(x => x.Dog.Owner.Dogs.Select(d => d.Color))
        .Include(x => x.Dog.Owner.Dogs.Select(d => d.Color1))
        .Include(x => x.Dog.Owner.Dogs.Select(d => d.HairLength))
        .Include(x => x.Dog.Owner.Dogs.Select(d => d.Sex))
        .Include(x => x.Dog.Owner.Address)
        .Include(x => x.Dog.Owner.Address.State)
        .Include(x => x.Dog.Owner.Phones)
        .Include(x => x.Dog.Owner.Emails)
        .Include(x => x.Dog.Owner.Phones.Select(p => p.PhoneType))
        .Include(x => x.Dog.Owner.Emails.Select(p => p.EmailType))
    where l.BarCode == BarCode
    select l).FirstOrDefault();
} // using the database

Here is a trimmed down view of the Owner and Dog classes.

Owner Class:

[DataMember]
public Nullable<System.DateTime> UpdatedOn { get; set; }
[DataMember]
public int ID { get; set; }

public virtual ICollection<Dog> Dogs { get; private set; }

Dog Class:

[DataMember]
public Nullable<System.DateTime> UpdatedOn { get; set; }
[DataMember]
public int ID { get; set; }

[DataMember]
public virtual Owner Owner { get; set; }

public virtual ICollection<License> Licenses { get; set; }

It works in the test client like this. If I make the ICollection Dogs or the ICollection Licenses a DataMember is when I get the StackOverflow.

So how can I get the collections to come across WCF?

Upvotes: 2

Views: 1462

Answers (1)

Salvador Sarpi
Salvador Sarpi

Reputation: 981

Use the ReferencePreservingDataContractFormat here.

And then mark your wcf service methods (operation contracts) with the attribute:

[OperationContract]
[ReferencePreservingDataContractFormat]
List<Dog> GetDogsAndOwners();

Upvotes: 4

Related Questions