micronyks
micronyks

Reputation: 55443

Json parsing in MVC 4 web api with angularjs

public partial class User
{
    public System.Guid UserId { get; set; }
    public Nullable<System.Guid> RoleId { get; set; }
    public Nullable<long> MembershipNo { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Gender { get; set; }
    public string Emaiil { get; set; }
    public Nullable<decimal> MobileNo { get; set; }
    public string Description { get; set; }
    public Nullable<System.Guid> ModifiedBy { get; set; }
    public Nullable<System.DateTime> ModifiedDate { get; set; }
    public virtual Role Role { get; set; }
 }

This is my table in DB named Users which is associated with Roles table of DB (as you can see last virtual row at the end above)

Now My problem is simple. I'm using angulars $http.get() method to call my Web Api in MVC 4. When i call it, it gets connected and fetches desired record but it doesn't throw proper result back to .js file or controller. At .js side I run into error. Every time, it executes .error(jsonResult,config,header,status) .

When I jump on to JsonResult, it shows me below error.

    Object
    ExceptionMessage: "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."
    ExceptionType: "System.InvalidOperationException"
    InnerException: Object
    ExceptionMessage: "Self referencing loop detected for property 'Role' with type
    'System.Data.Entity.DynamicProxies.Role_82CA96EA045B1EB47E58B8FFD4472D86502EEA79837B4AE3AD705442F6236E58'. 
    Path 'Role.Users[0]'."
    ExceptionType: "Newtonsoft.Json.JsonSerializationException"
    Message: "An error has occurred."

I don't know what's wrong here. Is it json parsing error or something? if so, I've heard and read the articles that webapi in .net handles or throws json itself.

My call happens through

 $http.get(apiUrl).success(function (jsonResult, header, config, status) {

    debugger;
    var number = parseInt(jsonResult.membershipNo) + 1;

    $scope.membershipNo = "M" + number;

})
.error(function (jsonResult, header, config, status) {
    debugger;
    toastr.error('Something went wrong ! Contact Administrator!!!');
});

Edited:

One more thing to mention, .CS side when I fetch single cell value (from DB/table) , it gets returned back to .success() call but when i fetch particular row or all rows, it gets returned to .error() call. I'm using entity frameworkd 6.1.1. and above class is generated by EF-6.1.1.


public partial class Role
{
public Role()
{
    this.Permissions = new List<Permission>();
    this.Users = new List<User>();
}

public System.Guid RoleId { get; set; }
public string RoleName { get; set; }
public string Description { get; set; }
public Nullable<System.Guid> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
public virtual ICollection<User> Users { get; set; }
}

Upvotes: 1

Views: 1105

Answers (2)

sylwester
sylwester

Reputation: 16498

Hi you can solve that in 2 easy steps

First Step: Create globalConfig class where you can set ignoring ReferenceLoopHandling (http://james.newtonking.com/json/help/index.html?topic=html/SerializationSettings.htm) and if you crating js app you can set as well to remove xml formaters and always get return from Webapi as JSON string is usefull for debugging. So in your app_start folder add class GlobalConfig like below:

public class GlobalConfig
  {
                    public static void CustomizeConfig(HttpConfiguration config)
                    {
                        // Remove Xml formatters. This means when we visit an endpoint from a browser,
                        // Instead of returning Xml, it will return Json.
                        //that is optional

                        config.Formatters.Remove(config.Formatters.XmlFormatter);   
                       GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = 
    Newtonsoft.Json.ReferenceLoopHandling.Ignore;

                    }
}

Second Step: In Global.asax set your custom configuration to do that please add code below to method Application_Start():

 GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);

Upvotes: 1

cpoDesign
cpoDesign

Reputation: 9143

it sounds like: the problem is that EF is using lazy loading that is not materialized in time of constructing this, on role. EF from early version has switched lazy loading on by default.

Suggested solution Create subset of you user class, with the parts that you really need. => Its bad practise to fetch too much data that you are not gonna need.

Upvotes: 1

Related Questions