Search code examples
c#jsonasp.net-mvcnestedjavascriptserializer

How to serialize a nested entity (model) with JavascriptSerializer in C#?


I am building a ASP.NET webapplication and I am also working with Entity Framework Code First. In this case I am using two entities (Customer and Contact) which have a One-to-Many relation with eachother (one Customer can have multiple Contacts). While getting the data from the database, everything goes fine. I also use Viewmodels, so next to my data entities, I also have two models called CustomerModel and ContactModel.

Below here I will show my entities and my viewmodels:

Customer-entity

[Table("Customer")]
    public class Customer
    {
        [Key()]
        public Guid Id { get; set; }
        //other non-relevant properties
        public virtual List<Contact> Contacts { get; set; }
    }

Contact-entity

[Table("Contact")]
    public class Contact
    {
        [Key()]
        public Guid Id { get; set; }
        //non-relevant properties
        [ForeignKey("Customer")]
        public Guid CustomerId { get; set; }
        [Required]
        public virtual Customer Customer { get; set; }
    }

CustomerModel

[Serializable]
    public class CustomerModel
    {
        public Guid Id { get; set; }
        //non-relevant properties
        [ScriptIgnore(ApplyToOverrides = true)]
        public virtual List<ContactModel> Contacts { get; set; }
    }

ContactModel

[Serializable]
    public class ContactModel
    {
        public Guid Id { get; set; }
        //non-relevant properties
        public Guid CustomerId { get; set; }
        [ScriptIgnore(ApplyToOverrides = true)]
        public virtual CustomerModel Customer { get; set; }
    }

When I run my application and the code as well, it all works fine in the backend until it needs to serialize it to JSON in my HomeController.

public ActionResult GetCustomerById(Guid id)
        {
            CustomerModel customer = new CustomerManager().GetById(id);
            string output = serializer.Serialize(customer);
            return Content(output);
        }

Even the CustomerModel object gets the 2 contacts, but at my Serialize(customer) method, it doesn't parse it to JSON. So actually, when I debug it and look at my output, I see every property but not the nested ContactModels.

In my case the string output doesn't contain the two Contacts. How do I solve this? I have checked some 'similar' questions on Stackoverflow as well but with no result.


Solution

  • Okay, i see you are missing a concept DTO and circular refferencing, in simplicity you must make a model of the content you want to deliver. What's biting you is layers/refferences, so I did away with all the loopyness in our models.

    Think of a -> b -> a that whould result in a json looking something like this

    { a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a}}}}}}}}}} //Into infinity and beyond }

    This is in essence what you want.

    public JsonResult GetCustomerById(Guid id)
    {
        CustomerModel customer = new CustomerManager().GetById(id);
        CustomerResultModel output = new CustomerResultModel(){
            id = customer.Id,
            Contacts = GetContacts(customer.Contacts)
        };
        return Json(output, JsonRequestBehavior.AllowGet); 
        //If you only POST then remove the AllowGet (the action name says Get so I'm assuming
    }
    private IEnumerable<ContactResultModel> GetContacts(Contacts){
        foreach(var a in Contacts){
            //When you use the yield keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator.
            yield return new ContactResultModel(){            
                Id  = a.Id,
                CustomerId = a.CustomerId
            };
        }
    }
    

    Models

    class CustomerResultModel{
        public Guid id {get;set;}
        public IEnumerable<ContactResultModel> Contacts {get;set;}
    }
    
    class ContactResultModel{
        public Guid id {get;set;}
        public Guid CustomerId {get;set;}
    }