Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 序列化类型为';的对象时检测到循环引用;SubSonic.Schema.DatabaseColumn';。_C#_.net_Json_Entity Framework_Subsonic - Fatal编程技术网

C# 序列化类型为';的对象时检测到循环引用;SubSonic.Schema.DatabaseColumn';。

C# 序列化类型为';的对象时检测到循环引用;SubSonic.Schema.DatabaseColumn';。,c#,.net,json,entity-framework,subsonic,C#,.net,Json,Entity Framework,Subsonic,我正在尝试做一个简单的JSON返回,但我有以下问题 public JsonResult GetEventData() { var data = Event.Find(x => x.ID != 0); return Json(data); } 我得到一个HTTP 500,例外情况如这个问题的标题所示。我也试过了 var data = Event.All().ToList() 这就产生了同样的问题 这是bug还是我的实现?在对象层次结构中似乎存在JSON序列化程序不支持的循

我正在尝试做一个简单的JSON返回,但我有以下问题

public JsonResult GetEventData()
{
    var data = Event.Find(x => x.ID != 0);
    return Json(data);
}
我得到一个HTTP 500,例外情况如这个问题的标题所示。我也试过了

var data = Event.All().ToList()
这就产生了同样的问题


这是bug还是我的实现?

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

return Json(new 
{  
    PropertyINeed1 = data.PropertyINeed1,
    PropertyINeed2 = data.PropertyINeed2
});

这将使您的JSON对象更轻、更容易理解。如果您有许多属性,则可以用来在DTO对象和View对象之间进行映射。

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

root B => child A => parent B => child A => parent B => ...
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
           );
}

通常有几种方法可以禁用沿特定路径的导航;例如,使用
XmlSerializer
可以将父属性标记为
XmlIgnore
。我不知道这个json序列化程序是否可行,也不知道
DatabaseColumn
是否有合适的标记(不太可能,因为它需要引用每个序列化API)

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

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

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

root B => child A => parent B => child A => parent B => ...
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
           );
}
如果您不希望对象位于
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
           );
}

这是因为新的DbContext T4模板用于生成EntityFramework实体。为了能够执行更改跟踪,此模板使用代理模式,将漂亮的POCO包装在一起。这会导致在使用JavaScriptSerializer序列化时出现问题

public string GetEntityInJson()
{
   JavaScriptSerializer j = new JavaScriptSerializer();
   var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
   return j.Serialize(entityList );
}
那么这两种解决方案是:

  • 要么只是序列化并返回客户端上所需的属性
  • 您可以通过在上下文的配置上设置来关闭代理的自动生成

    context.Configuration.ProxyCreationEnabled=false

  • 在下面的文章中有很好的解释


    避免直接转换表对象。如果在其他表之间设置了关系,则可能会引发此错误。
    相反,您可以创建一个模型类,为类对象赋值,然后序列化它。

    我也遇到了同样的问题,通过使用Newtonsoft.Json解决了这个问题

    var list = JsonConvert.SerializeObject(model,
        Formatting.None,
        new JsonSerializerSettings() {
            ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
    });
    
    return Content(list, "application/json");
    

    使用Newtonsoft.Json:在Global.asax应用程序_Start方法中添加以下行:

    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
    

    我正在使用修复,因为在MVC5视图中使用了敲除

    行动上

    return Json(ModelHelper.GetJsonModel<Core_User>(viewModel));
    
    返回Json(ModelHelper.GetJsonModel(viewModel));
    
    作用

       public static TEntity GetJsonModel<TEntity>(TEntity Entity) where TEntity : class
        {
            TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity;
            foreach (var item in Entity.GetType().GetProperties())
            {
                if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1)
                    item.SetValue(Entity_, Entity.GetPropValue(item.Name));
            }
            return Entity_;  
        }
    
    公共静态tenty GetJsonModel(tenty实体),其中tenty:class
    {
    TEntity Entity_u2;=Activator.CreateInstance(类型(TEntity))作为TEntity;
    foreach(Entity.GetType().GetProperties()中的变量项)
    {
    if(item.PropertyType.ToString().IndexOf(“Generic.ICollection”)=-1&&item.PropertyType.ToString().IndexOf(“SaymenCore.DAL”)=-1)
    item.SetValue(Entity,Entity.GetPropValue(item.Name));
    }
    返回实体;
    }
    
    //首先:创建一个类作为视图模型
    公共类事件视图模型
    {
    公共int Id{get;set}
    公共字符串属性1{get;set;}
    公共字符串属性2{get;set;}
    }
    //然后从你的方法
    [HttpGet]
    公共异步任务GetEvent()
    {
    var events=await db.Event.Find(x=>x.ID!=0);
    List model=events.Select(event=>neweventviewmodel(){
    Id=event.Id,
    Property1=event.Property1,
    Property1=event.Property2
    }).ToList();
    返回Json(新的{data=model},JsonRequestBehavior.AllowGet);
    }
    
    总之,有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;
            }
        }
    
    解决方案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);
            }
        }
    
    以下两种解决方案是相同的,但使用模型更好,因为它是强类型的。

    解决方案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);
            }
        }
    
        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);
            }
        }
    
    解决方案4:返回仅包含所需属性的新动态对象

        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);
            }
        }
    
        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);
            }
        }
    

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

    提供的答案很好,但我认为可以通过添加“架构”透视图来改进

    调查

    MVC的Controller.Json
    函数正在完成这项工作,但在这种情况下,它很难提供相关错误。通过使用
    Newtonsoft.Json.JsonConvert.SerializeObject
    ,该错误准确地指定触发循环引用的属性。这在序列化更复杂的对象层次结构时特别有用

    适当的架构

    千万不要尝试序列化数据模型(例如EF模型),因为ORM的导航属性是走向序列化的必经之路。数据流应如下所示:

    Database -> data models -> service models -> JSON string 
    
    可以使用自动映射器(例如)从数据模型中获取服务模型。虽然这不能保证缺少循环引用,但适当的设计应该做到这一点:服务模型应该准确地包含服务使用者所需的内容(即属性)

    在这些罕见的情况下,当客户端请求在不同级别上涉及同一对象类型的层次结构时,服务可以创建具有PAR的线性结构。