4

I am trying to fetch a complex ViewModel object to my view, via JQuery $.getJSON. However, although it works for simple objects, when my viewmodel contains other object lists as part of it, my Ajax request stops working.

This is how I fetch the data,

$.getJSON('/Company/GetCompanies', function(data) { 
    viewModel.model = ko.mapping.fromJS(data)
    ko.applyBindings(viewModel)
});

This is working viewmodel,

public class CompanyIndex
{
    public IList<CompanyWithDetail> Companies { get; set; }

    public void FillCompanies()
    {
        UnitOfWork unitOfWork = new UnitOfWork();
        unitOfWork.CompanyRepository.SetProxy(false);
        var CompanyFromDB = unitOfWork.CompanyRepository.GetCompanyWithDetails();

        Companies = new List<CompanyWithDetail>();
        foreach (Company company in CompanyFromDB)
        {
            CompanyWithDetail newCompany = new CompanyWithDetail();
            newCompany.CompanyName = company.CompanyName;
            Companies.Add(newCompany);

        }
        unitOfWork.Dispose();
    }
}

This is the CompanWithDetail class,

// For sake of demonstration it only contains name
public class CompanyWithDetail
{
    public string CompanyName { get; set; }
}

This is working fine. However, when I add

public IList<CompanyFaxNumber> FaxNumber { get; set; }

this property to CompanyWithDetail class, and fill it in FillCompanies() method of CompanyIndex viewmodel, my ajax get request stops working.

This is my controller btw, in both cases it returns the correct data, but jquery $.getJSON does not receive when I add complex objects.

public ActionResult GetCompanies()
{
    var model = new CompanyIndex();
    model.FillCompanies();
    return Json(model ,JsonRequestBehavior.AllowGet);   
}

EDIT 1:

By saying getJSON does not receive the data, I mean the body of function is not executed.

$.getJSON('/Company/GetCompanies', function(data) { 
    alert('test')
});

For instance, alert is working when there is no complex object but it stops working when I add objects to viewmodel.


EDIT 2

This is the error when I call 'Company/GetCompanies' from browser instead of ajax.

A circular reference was detected while serializing an object of type 'CompanyManagement.Models.CompanyEmail'.


Do i need to do something special to pass complex objects from controller to view ? Any ideas?

emre nevayeshirazi
  • 18,983
  • 12
  • 64
  • 81

3 Answers3

4

Do i need to do something special to pass complex objects from controller to view ?

Yes, you should use view models. You cannot JSON serialize object hierarchies that conatin circular references between them. You will have to break those circular references if you want to be able to JSON serialize your model and send it over the wire. The JSON serialization format simply doesn't support this.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    +1 for the old "Use View Models" which I'm sure will be your epitaph... ;-) – Tom Chantler Jul 05 '12 at 08:58
  • 1
    **Use View Models and stop passing your domain models to the views**. This sentence solves 99.99% of the problems that people encounter when developing ASP.NET MVC applications. If only all developers could follow this advice, the `asp.net-mvc` tag would have been a lonely place on Stack Overflow :-) Unfortunately all this EF and CodeFirst stuff provides way too many temptations to those developers and they quickly fall into the trap. – Darin Dimitrov Jul 05 '12 at 08:59
  • I see your point. I need most of the properties of model itself on view. That is why I used these models in my viewmodel directly. Thanks will avoid that in future. – emre nevayeshirazi Jul 05 '12 at 08:59
1

Default JSON serializer is not capable of handling circular references. You probably have Company with Emails property, and each Email has a reference to a Company again.

You'll either need to send a view model, as Darin suggested (that's the best practice anyway):

http://blog.davebouwman.com/2011/12/08/handling-circular-references-asp-net-mvc-json-serialization/

...or you could replace default JSON serializer with something like Json.NET which can handle circular references:

Circular reference exception when serializing LINQ to SQL classes

Community
  • 1
  • 1
Miroslav Popovic
  • 12,100
  • 2
  • 35
  • 47
0

You can simply do a ajax post call using dataType= json

    $.ajax({
                type: 'POST',
                url: '@Url.Action("actionName", "controllerName")',
            data: JSON.stringify({ *Perameter If Any* }),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (result) {                  
                  if (result != null) {

                } else {


                }
            }
           });

And you action method should be a Json result

public JsonResult ActionName(perameter)
    {

            var modle= getobject();
            return Json(modle);
  }

In above case value you will receive in success method of ajax call that is result will be the exact same object you sent... No need to serialize or any tricks.. Simple as it looks

waheed Asghar
  • 95
  • 1
  • 8