Gerald Hughes
Gerald Hughes

Reputation: 6159

A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies'

I have a Asp.NET MVC project, database first. I have an Create action in Place controller. In the action method I get my data like this:

// GET: /Place/Create
[Authorize]
public ActionResult Create()
{
    string userId = User.Identity.GetUserId();
    var places = db.Places.Where(p => p.UserId == userId);

    var placesVM = new PlacesVM(places);

    ViewBag.UserId = new SelectList(db.AspNetUsers, "Id", "UserName");
    return View(placesVM);
}

My Place view model looks like this:

public class PlacesVM
{
    public IQueryable<Place> Places { get; set; }
    public Place Place { get; set; }

    public PlacesVM(IQueryable<Place> places)
    {
        Places = places;
        Place = new Place();
    }
}

My Place Model:

public partial class Place
    {
        public string Id { get; set; }
        public string UserId { get; set; }
        //TODO: Validare cordonate
        public decimal X { get; set; }
        public decimal Y { get; set; }

        [Display(Name = "Title")]
        [Required]
        [StringLength(250, MinimumLength = 5)]
        public string Titlu { get; set; }

        [Display(Name = "Description")]
        [Required]
        [StringLength(500, MinimumLength = 10)]
        public string Descriere { get; set; }

        [Required]
        [Range(0, 1)]
        public byte Public { get; set; }

        public virtual AspNetUser AspNetUser { get; set; }
    }

AspNetUser:

public partial class AspNetUser
    {
        public AspNetUser()
        {
            this.AspNetUserClaims = new HashSet<AspNetUserClaim>();
            this.AspNetUserLogins = new HashSet<AspNetUserLogin>();
            this.Places = new HashSet<Place>();
            this.UserComments = new HashSet<UserComment>();
            this.AspNetRoles = new HashSet<AspNetRole>();
        }

        public string Id { get; set; }
        public string UserName { get; set; }
        public string PasswordHash { get; set; }
        public string SecurityStamp { get; set; }
        public string Discriminator { get; set; }

        public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }
        public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }
        public virtual ICollection<Place> Places { get; set; }
        public virtual ICollection<UserComment> UserComments { get; set; }
        public virtual ICollection<AspNetRole> AspNetRoles { get; set; }
    }

Now I would like to use Model.Places proprietes in the javascript part of the page. How can I do this?

I've tried to the following:

<script>
    var model = '@Html.Raw(Json.Encode(Model))';
</script>

But I got this error:

{"A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Place_084A987E8F6FBE574A22E813FE314F2894AF728F244BDD6582AF50929FF1161D'."}

I have checked the following links on SO, but didn't manage to solve my problem:

Upvotes: 0

Views: 1645

Answers (1)

user3559349
user3559349

Reputation:

You PlacesVM view model contains a property that is typeof Place which in turn contains a property which is typeof AspNetUser which in turn contains a property which is typeof Collection<Place>.

When the Json.Encode() method serializes you model, it serializes Place which then serializes AspNetUser which then serializes each Place which throws the error, because if allowed to continue, it would serialize each AspNetUser and so on and so on until the system ran out of memory.

Change you view model to include only those property that you need in the view - refer What is ViewModel in MVC?. Note that a view model should not generally contain properties which are data models, particularly when you editing data in a view. Instead, copy the properties from Place into PlaceVM that you need to edit, except AspNetUser, and if you need to display some properties of AspNetUser, then just include additional properties for then, for example public string UserName { get; set; }.

Side note: Your current view model does not contain a default (parameterless) constructor so the DefaultModelBinder will throw an exception when you submit.

Upvotes: 2

Related Questions