JavaScriptSerializer circular reference when using ScriptIgnore

bflemi3 picture bflemi3 · Jan 28, 2013 · Viewed 8.1k times · Source

I have my Entity Framework Entities split out into a separate class library from my web project and data access layer. In my controller I make a call to my repository to get an IEnumerable<RobotDog.Entities.Movie> and then try to serialize into json using JavaScriptSerializer but I get a circular reference even though I'm using the [ScriptIgnore] attribute.

IMPORTANT: Originally I had my entities, data access and web all under one project and I was able to successfully serialize my entites without a circular reference. When I created separate layers that's when I started having problems. I did not change any of the entities.

An example of one of my entities in the RobotDog.Entities namespace:

namespace RobotDog.Entities {
    public class Character {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [MaxLength(200)]
        public string Name { get; set; }

        public virtual Person Person { get; set; }

        [ScriptIgnore]
        public virtual Movie Movie { get; set; }
    }
}

My controller:

namespace RobotDog.Web.Controllers {
    public class MoviesController : Controller {
        private UnitOfWork _unitOfWork = new UnitOfWork();

        [HttpGet]
        public ActionResult Index() {
            var user = Membership.GetUser(User.Identity.Name);
            if(user != null) {
                var movies = _unitOfWork.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey).Select(m => m.Movie);
                var serializer = new JavaScriptSerializer();
                var json = serializer.Serialize(movies);
                return View(json);
            }
            return View();
        }

    }
}

My Repository:

namespace RobotDog.DataAccess.Movies {
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
        internal MovieContext Context;
        internal DbSet<TEntity> DbSet;

        public Repository(MovieContext context) {
            if (context == null)
                throw new ArgumentNullException("context");

            Context = context;
            DbSet = Context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null ) {
            IQueryable<TEntity> query = DbSet;

            if (predicate != null)
                query = query.Where(predicate);

            return orderBy != null ? orderBy(query).ToList() : query.ToList();
        }
    }
}

Answer

Đonny picture Đonny · Jun 14, 2013

Maybe kinda late response, but I had similar problem with POCO Classes for Entity Framework Code-Firts. The problem was that may properties were declared as virtual. In this case EF creates proxy class which overrides the virtual property. It seems that ScriptIgnore attribute is not by default applied on overriden properties, unless you use it like this:

[ScriptIgnore(ApplyToOverrides=true)]