序列化"SubSonic.Schema .DatabaseColumn"类型的对象时检测到循环引用.

Jon*_*Jon 166 .net c# subsonic json entity-framework

我正在尝试做一个简单的JSON返回,但我遇到了问题,我有以下内容.

public JsonResult GetEventData()
{
    var data = Event.Find(x => x.ID != 0);
    return Json(data);
}
Run Code Online (Sandbox Code Playgroud)

我得到了一个HTTP 500,例外情况如此问题的标题所示.我也试过了

var data = Event.All().ToList()
Run Code Online (Sandbox Code Playgroud)

这给了同样的问题.

这是一个错误还是我的实现?

Dar*_*rov 173

似乎您的对象层次结构中存在循环引用,JSON序列化程序不支持该引用.你需要所有的栏目吗?您只能在视图中选择所需的属性:

return Json(new 
{  
    PropertyINeed1 = data.PropertyINeed1,
    PropertyINeed2 = data.PropertyINeed2
});
Run Code Online (Sandbox Code Playgroud)

这将使您的JSON对象更轻松,更容易理解.如果您有许多属性,AutoMapper可用于在DTO对象和View对象之间自动映射.

  • Automapper并不能保证您不会遇到此问题.我来到这里寻找答案,我实际上正在使用automapper. (7认同)

ddf*_*fal 99

我有同样的问题并解决了 using Newtonsoft.Json;

var list = JsonConvert.SerializeObject(model,
    Formatting.None,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});

return Content(list, "application/json");
Run Code Online (Sandbox Code Playgroud)

  • 这应该被标记为最佳答案,因为它涵盖了您无法花费数小时将对象转换为其他表示形式的情况,如标记为已接受的答案. (5认同)
  • 这个内联代码对我来说很好.kravits88提到的全局配置中的相同内容对我不起作用.此外,应更新方法签名以返回此代码的ContentResult. (3认同)

Cla*_*oom 54

这实际上是因为复杂对象是导致生成的json对象失败的原因.它失败了,因为当对象被映射时,它映射了映射其父对象的子对象,从而进行循环引用.Json将花费无限的时间来序列化它,因此它可以防止异常的问题.

实体框架映射也会产生相同的行为,解决方案是丢弃所有不需要的属性.

只是说明最终答案,整个代码将是:

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           new {
                Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
               }
           , JsonRequestBehavior.AllowGet
           );
}
Run Code Online (Sandbox Code Playgroud)

如果您不想要Result属性中的对象,也可以是以下内容:

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
           , JsonRequestBehavior.AllowGet
           );
}
Run Code Online (Sandbox Code Playgroud)


Amr*_*mro 13

总结一下,有4个解决方案:

解决方案1:关闭DBContext的ProxyCreation并最终将其恢复.

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        bool proxyCreation = db.Configuration.ProxyCreationEnabled;
        try
        {
            //set ProxyCreation to false
            db.Configuration.ProxyCreationEnabled = false;

            var data = db.Products.ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
        finally
        {
            //restore ProxyCreation to its original state
            db.Configuration.ProxyCreationEnabled = proxyCreation;
        }
    }
Run Code Online (Sandbox Code Playgroud)

解决方案2:通过设置ReferenceLoopHandling使用JsonConvert忽略序列化设置.

    //using using Newtonsoft.Json;

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.ToList();

            JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
            var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss);

            return Json(result, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }
Run Code Online (Sandbox Code Playgroud)

以下两个解决方案是相同的,但使用模型更好,因为它是强类型的.

解决方案3:返回仅包含所需属性的模型.

    private DBEntities db = new DBEntities();//dbcontext

    public class ProductModel
    {
        public int Product_ID { get; set;}

        public string Product_Name { get; set;}

        public double Product_Price { get; set;}
    }

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new ProductModel
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }
Run Code Online (Sandbox Code Playgroud)

解决方案4:返回一个新的动态对象,其中仅包含所需的属性.

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }
Run Code Online (Sandbox Code Playgroud)


Mar*_*ell 7

JSON与xml和其他各种格式一样,是一种基于树的序列化格式.如果在对象中有循环引用,它将不会爱你,因为"树"将是:

root B => child A => parent B => child A => parent B => ...
Run Code Online (Sandbox Code Playgroud)

通常有一些方法可以沿某条路径禁用导航; 例如,XmlSerializer您可以将父属性标记为XmlIgnore.我不知道这是否可能与json序列化器有关,也不知道是否DatabaseColumn有合适的标记(非常不可能,因为它需要引用每个序列化API)


Mis*_*eró 6

添加[JsonIgnore]到模型中的虚拟属性。


kra*_*s88 5

使用 Newtonsoft.Json:在您的 Global.asax Application_Start 方法中添加以下行:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
Run Code Online (Sandbox Code Playgroud)