如何解决循环引用警告怎么处理JSON序列化

以前都是到处看博客,今天小菜也做点贡献,希望能帮到大家.
废话不多说,直接进入正题.
用过.net MVC的同学应该都被json序列化报循环引用错误这个问题骚扰过.网上有一些解决办法,但是都治标不治本.如在引发异常的属性上加上[ScriptIgnore]或者[JsonIgnore],又或者用db.Configuration.ProxyCreationEnabled =这些解决办法都存在问题且需要多处修改并且测试.本小菜之前一直被其骚扰,就在前两天我决定一定要找到比较优的解决办法,google一顿查,各种查,终于在一个老外的文章中找到办法,但是当时光顾考代码看来着忘记链接了....,核心思想就是用json.net替换mvc默认的json序列化类,因为json.net官方给出了解决循环引用的配置选项.
step1 在项目上添加Newtonsoft.Json引用
step2 在项目中添加一个类,继承JsonResult,代码如下
public class JsonNetResult : JsonResult
public JsonSerializerSettings Settings { get; private set; }
public JsonNetResult()
Settings = new JsonSerializerSettings
         //这句是解决问题的关键,也就是json.net官方给出的解决配置选项.
          ReferenceLoopHandling = ReferenceLoopHandling.Ignore
public override void ExecuteResult(ControllerContext context)
if (context == null)
throw new ArgumentNullException("context");
if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException("JSON GET is not allowed");
HttpResponseBase response = context.HttpContext.R
response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentT
if (this.ContentEncoding != null)
response.ContentEncoding = this.ContentE
if (this.Data == null)
var scriptSerializer = JsonSerializer.Create(this.Settings);
using (var sw = new StringWriter())
scriptSerializer.Serialize(sw, this.Data);
response.Write(sw.ToString());
step3 在项目中新建一个BaseController,继承Controller类,然后重写Controller中的json方法,代码如下
public class BaseController : Controller
protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
return new JsonNetResult
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior };
step 4 在你自己的controller类中,继承之前的BaseController,然后使用示例如下
[HttpPost]
public JsonResult GetUserList()
User user = UserHelper.GetCurrentUser();
List&User& users = userService.GetCompanyUsers(user.Units.FirstOrDefault().ID,user.ID);
//此时json方法会调用你重写的json方法
          return Json(users);
catch (Exception ex)
return Json(CommonException.GetError(ex));
这样就可以解决循环引用的问题了.亲测好用.
菜鸟一枚,有不对的地方希望前辈们指点,谢谢.
阅读(...) 评论()EntityFramework Model有外键时,Json提示循环引用 解决方法
 正文之前先说两句,距离上篇博客已将近两个月,这方面的学习和探索并没有停止,而是前进道路上遇上了各种各样的问题,需要不断的整理、反思和优化,这段时间的成果,将在最近陆续整理发出来。
个人感觉国内心态太浮躁了,很少有能深入研究下去并将自己经验分享的人,可能很忙,也可能嫌麻烦。特别是面向新技术,尤其是在学习资料有限的情况下,愿意花费时间摸索和分享的人实在太少太少,遇到问题,搜索结果一抓一大把,但是往往都是转载,连最起码的自己验证都没有,结果就是以讹传讹,不仅对解决问题无用,反而容易产生误导。最近这段时间感触颇深,遇到问题往往需要去认真考虑选择合适英文关键词从英文网站里找解决方案。
这块技术,我也是新手,遇到的问题比较多,我发现以现在的水平和能力写成一个逻辑性比较强的系列很有难度,因此决定从点入手,将发现问题-》寻找解决方法-》最终解决方法整个过程记录下来,最后再将一个个点串起来,形成线。作为自己的总结和反思,也为后来者提供一些经验和帮助,能少走一些弯路。同时,也留下一些目前无法解决的问题,欢迎交流,欢迎指正。
好了,转入正文,采用operamasks-ui2.0 +MVC4.0+EF5.0这种模式或者说架构,首先面对的是一个不可避免的问题,前后台交换数据,目前最流行、最高效的方式就是Json(上去几年可能用xml的多一些,关于Json和xml的优缺点,不在此处描述,有兴趣的自己查资料吧)。也就是数据通过EF取出来,这时候是对象,通过MVC调度,经过序列化转换成Json格式,传给前台,前台开发框架(operamasks-ui或easyui或extJS甚至Jquery等等)接收后进行解析和展现。这个时候问题就来了,如何序列化?如果没做过这块开发,会觉得这很简单,包括我在之前的系列里也提到过,自己为object写了一个扩展方法:
public static string ToJsonString(this Object obj)
JavaScriptSerializer s = new JavaScriptSerializer();
StringBuilder sb = new StringBuilder();
s.Serialize(obj, sb);
return sb.ToString();
然后在控制器里做以下处理
public ActionResult GetMenu()
IQueryable&Menu& menu = MenuService.Query();
var nodes = new List&TreeNode&();
foreach (var item in menu.ToList())
TreeNode node = new TreeNode();
node.id = item.ID;
node.pid = item.ParentID;
node.text = item.N
node.url = item.U
node.expanded = "true";
nodes.Add(node);
return Content(nodes.ToJsonString());
事实上,上面的方式是多此一举,完全没必要。更简便的做法是,直接调用Json(object)方法就行了,也即把上面的return Content(nodes.ToJsonString());替换为return Json(nodes);。其实,我在写扩展方法实现序列化之前,用过这种方式,结果发现前台接收不到数据,才自己又去查找资料,使用JavaScriptSerializer类序列化对象,采用return Content(序列化后的Json)方式。至于当初为什么不好用,原因也找到了,一个小细节,也是新手常犯的一个错误,在这也说一下。问题不是出在序列化对象为Json格式上,而是http协议的方法上。对,你没看错,就是http协议,前台通过ajax调用后台方法的时候,一定注意是Get还是Post,如果是Get,那么默认情况下,控制器里的方法处理完毕后,调用Json(object)是禁止Get获取的,而是必须调用其重载函数return
Json(object, JsonRequestBehavior.AllowGet);这个问题很隐蔽,不知道这么回事,就会莫名其妙,明明后台调试传回了数据,但前台死活就接收不到数据。还有一个隐含的地雷就是,你在使用一些前台框架的一些控件的时候,往往只调用其方法,而其内部往往也是通过ajax来加载和刷新数据的,一不留意,也会发生上述问题,导致前台取不到数据。
上面篇幅不小,其实只说了一个小问题,为下文做一下铺垫。
下面就来说核心问题。采用EntityFramework,采用Code First模式,先定义实体类,类有普通属性和导航属性。以部门为例,这是一种常见的自关联模式,即定义一个字段,指向其上级部门,从而形成无限级层次扩展,很明显,这是一种一对多关系,即一个部门只有一个上级部门,而可能有多个下级部门。如下所示(已做简化处理,未包括一些无关属性)。
class Department
[DisplayName("内码")]
public string ID { get; set; }
[DisplayName("部门名称")]
public string Name { get; set; }
public string ParentID { get; set; }
[DisplayName("上级部门")]
[ForeignKey("ParentID")]
public virtual Department ParentDept { get; set; }
public virtual ICollection&Department& SonDepts { get; set; }
通过使用ForeignKey属性标记,可以实现自主指定映射成数据库的字段名称。如果不使用,EF也能自动生成,不过要按约定的规则(类名+ID)来写属性名,我还是喜欢自己的地盘自己做主,自动生成容易出现指示不明、修改出错的问题。至于ForeignKey里面的参数怎么写,刚学习的时候也困惑了半天,这个ForeignKey应该标记在属性ParentID上呢还是标记在导航属性ParentDept上呢?里面的参数是不是要写对应外键的库表名称呢?试了试,好像有些写法就提示出错,有些就提示正常,提示正常的还不止一种写法。后来通过摸索和查资料,才知道两种方法都可以,其一就是我上面写的,标记在导航属性ParentDept上,参数为属性ParentID,另一种就是标记在属性ParentID,里面参数是导航属性ParentDept,即
   [ForeignKey("ParentDept")]
public string ParentID { }
public virtual Department ParentDept { }
   现在回过头来觉得这样相互定义很自然,但当初的时候确实为究竟该怎么写才对困扰了一阵。
   继续说正文。对于一对多关系,EF处理模式,就是加一个导航属性,指明上级,再加一个导航属性,指明下级,就像上面写的
   public virtual Department ParentDept { }
public virtual ICollection&Department& SonDepts { }
   当初我也是这样做的,完全是照网上一些教程做的。可以说,这样做本身其实也没什么问题,但序列化成Json对象的时候,就出了大问题,你会得到一个错误提示:序列化类型为XX的对象时检测到循环引用。刚看到这个错误的时候可能会觉得莫名其妙,为什么会报这个错误呢?其实原理很简单,序列化的时候,先找个一个部门A,然后有下级部门的导航属性,序列化下级部门B的时候,其上级部门的导航属性指向了部门A,结果就是循环引用,跟死循环一个道理。
如何解决这个问题呢?有一种解决方式,就是使用linq to entity,把基本属性取出来,抛弃掉导航属性,但这种方式局限性比较大,需要将实体类的非导航属性字段人工写一遍,很繁琐,通用性差,并且抛弃了引用属性,延迟加载的优点也丢了。
   那么有没有更优的解决方式呢?
  我从网上查资料,有人说将db.ContextOptions.ProxyCreationEnabled=false; 也有人说 将db.ContextOptions.LazyLoadingEnabled=false,还有人说为导航属性加上[ScriptIgnore]标记,我实际试过,没用,我觉得不是MVC版本问题,而是这根本就不是问题的本质,传这些资料的人根本就没自己验证过是否真有用。事实上,只要导航属性有Virtual关键字,那么EF就会延迟加载,序列化的时候就会发生循环引用,这才是问题的本质。既然找到了问题本质,那解决是不是也很简单了,把virtual关键字去掉就行了。这样做确实可行,序列化的时候不会报循环引用错误,但是,这样做的时候,EF延迟加载的优点也彻底被抛弃了。比如说,如果有延迟加载,你完全可以在视图里直接用model=&model.ParentDept.Name来绑定显示部门名称,不用写任何代码。如果没有延迟加载,那么,model.ParentDept对象就是null,你需要在控制器的方法里通过DbSet
&Department&.Find(ParentID)方法找到并实例化一个Department对象,然后将名称通过ViewBag这个动态对象传递给前台,你可以想象一下,这有多繁琐。
如何既能排除掉循环引用的雷,又能保留延迟加载的优点呢?查阅了大量资料,然后试验各种所谓的解决方案,最终,在一家国外网站上找到了解决方法,就是定义序列化Json的行为,使其忽略引用对象(导航属性),在MVC Web应用程序的App_Start目录的WebApiConfig.cs文件的Register方法末尾追加一句,只需要一句:
  config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling= Newtonsoft.Json.PreserveReferencesHandling.O
  其实原文还有一句config.Formatters.Remove(config.Formatters.XmlFormatter);
这句跟问题无关,不要加。当然老外同样有以讹传讹的人士存在,说加config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling= Newtonsoft.Json.ReferenceLoopHandling.I以及config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.S这两种方法看上去有效,经过实际验证无效。
  加了这句还不算完,你还需要在实体类中,一对多关系情况下,只保留其中一个导航属性,上面部门的例子里,你保留ParentDept可以,保留SonDepts也行,只保留一个,EF能正确识别出来这是一对多,库表中生成正确的外键。如果你仍然两个导航属性都留着,那么恭喜你,你还是会得到循环引用的错误提示。
采用上面的方式,你就可以为导航属性加上virtual关键字了,也可以保留ef延迟加载的优点了。
文章到这还没完,还有个尾巴。关系里还有一种常见的,就是多对多,比如角色和人员,一个角色有多个人员,一个人员有多个角色,按照教程,应该在人员实体类里加一个导航属性public virtual ICollection&Role& Roles { }, 在角色实体类里加一个导航属性public virtual ICollection&User& Users { },ef会自动识别,然后生成一张只有UserID和RoleID两个字段的中间库表。这一切看上去都没问题,就是常规的处理方式。但是,你在序列化成Json的时候,又会遭遇循环引用这颗雷,即使是按我上面那样那样去设置,仍然避免不了,想一想,依旧是死循环。
后来我想出了一个办法,就是自己定义一个中间实体,名字是RoleUser,然后,在User实体类里加public virtual ICollection&RoleUser& RoleUsers { },在Role实体类中加public virtual ICollection&RoleUser& RoleUsers { },也就是,一个多对多关系转成了两个一对多,采用上面的方式就能处理了。这样还有一个优点,就是可以在中间关系映射表中增加其他字段,比如创建时间、创建人,以及一些必要的业务信息,比如在学生的选课记录上增加成绩字段。
以上就是我自己摸索出来的解决方式,就目前来说,是自己能想到的最优解决方式,供大家参考下,欢迎批评指正,提供更佳的实现方式。
  可能是EF用的人还不多,但是Hibernate应该同样有类似问题吧,没接触过Hibernate,也欢迎了解Hibernate人说下在这方面是如何处理的。
日补充修正:
  本文发表后,有两位朋友留言提出自己的办法,一是用JsonIgnore属性,二是用DataContractJsonSerializer类,看上去貌似有用,经过试验,发现还是无效,不过也进一步提供了思路。其实文章整理出来后,就发现问题其实很简单了,就是序列化对象的时候如何处理循环引用的问题,只要为序列化类指定行为,那么一切问题也就解决了。其实我一直有点不踏实,就是我原来琢磨出来的方法,在WebApiConfig.cs里加对Json类的控制,是否真的能起作用?之前不了解WebApi,又查了下资料,发现跟普通的Control调用是两回事,也就意味着,不论在里面做什么,不应该对现有的Controller里面的方法产生影响。方向搞错了……进而想一下,如果去掉那段修改的代码,那么我的程序应该也能运行,于是试了一下,果然正常……只要将一对多关系只保留一个导航属性,那么自然就不存在循环引用的问题,我以为正确的解决方法,是在反复试验和多处修改后产生的混乱错觉,由此差点也成为误导别人的凶手……
  前面的摸索并不都是无用功,对这块了解已经深入了,也有了新的想法。方向明确了,就是为序列化类指定行为来控制序列化时的行为。那么如何来控制呢,前面用JavaScriptSerializer类为object类写过扩展方法,明显没有可控的属性,而之前的摸索也知道了Newtonsoft.Json.JsonConvert这个类可以控制循环应用的行为处理,尝试改了一下之前的扩展方法,果然可以。
  之前一直怀疑Controller.Json方法默认内部调用的是JavaScriptSerializer类来序列化对象的,按这个思路搜了一下,果然发现有人深入研究过,网址见,是通过查看MVC源码获取的,并且提供了如何继承默认Controller和重载Json方法,把序列化的JavaScriptSerializer替换成Newtonsoft.Json.JsonConvert的方法,看上去逻辑上没问题,具体没验证。考虑到这种方式比较麻烦,且以后升级MVC版本容易出问题,还是用我以前写的扩展方法来解决最为方便。
为Oject对象增加ToJsonString方法(注意对项目添加Newtonsoft.Json.dll引用)
using System.T
using System.Web.Script.S
using Newtonsoft.J
namespace Common.Extentions
public static class ObjectExtentions
public static string ToJsonString(this Object obj)
JsonSerializerSettings jsSettings = new JsonSerializerSettings();
jsSettings.ReferenceLoopHandling = ReferenceLoopHandling.I
return JsonConvert.SerializeObject(obj, jsSettings);
然后在Control里,获取到数据对象后,return Content(data.ToJsonString());
这样处理后,你可以在一对多关系中,同时使用两个导航属性,并且都添加virtual关键字,从而保留延迟加载特性。
  由此想到多对多关系也可以常规化处理了,不过你想为中间表增加字段,还得用上文拆分的思路,欢迎验证,欢迎指正。
json数据格式转换问题 循环引用
递归算法:解决hibernate实体外键关联,导致json解析死循环!
Struts2+json实现ajax,bean有外键实体hibernate懒加载导致
Java实体类转Json出现的一些问题
实体类含有自身或者另一个实体时转json
MySQL删除表的时候忽略外键约束
.net mvc 外键表数据读取
解决fastjson内存对象重复/循环引用json错误
json数据避免$ref 循环引用
JSON工具学习记录--FastJSON循环引用问题
没有更多推荐了,只是一只在程序猿道路的蚂蚁。
解决fastjson内存对象重复/循环引用json错误
什么是重复/循环引用
简单说,重复引用就是一个集合/对象中的多个元素/属性同时引用同一对象,循环引用就是集合/对象中的多个元素/属性存在相互引用导致循环。
List&Object& list = new ArrayList&&();
Object obj = new Object();
list.add(obj);
list.add(obj);
// 循环引用的特殊情况,自引用
Map&String,Object& map = new HashMap&&();
map.put("map",map);
// map1引用了map2,而map2又引用map1,导致循环引用
Map&String,Object& map1 = new HashMap&&();
Map&String,Object& map2 = new HashMap&&();
map1.put("map",map2);
map2.put("map",map1);
循环引用会触发的问题
暂时不说重复引用,单说循环引用。
一般来说,存在循环引用问题的集合/对象在序列化时(比如Json化),如果不加以处理,会触发StackOverflowError异常。
分析原因:
当序列化引擎解析map1时,它发现这个对象持有一个map2的引用,转而去解析map2。解析map2时,发现他又持有map1的引用,又转回map1。如此产生StackOverflowError异常。
FastJson对重复/循环引用的处理
首先,fastjson作为一款序列化引擎,不可避免的会遇到循环引用的问题,为了避免StackOverflowError异常,fastjson会对引用进行检测。
如果检测到存在重复/循环引用的情况,fastjson默认会以“引用标识”代替同一对象,而非继续循环解析导致StackOverflowError。
以上文两例说明,查看json化后的输出
重复引用 JSON.toJSONString(list)
//obj的实体
"$ref": "$[0]"
//对obj的重复引用的处理
2.循环引用 JSON.toJSONString(map1)
// map1的key:value对
// map2的key:value对
// 指向map1,对循环引用的处理
"$ref": ".."
引用标识说明:
“$ref”:”..” 上一级
“$ref”:”@” 当前对象,也就是自引用
“$ref”:”$” 根对象
“$ref”:”$.children.0” 基于路径的引用,相当于root.getChildren().get(0)
关闭FastJson的引用检测
JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);
FastJson提供了SerializerFeature.DisableCircularReferenceDetect这个序列化选项,用来关闭引用检测。关闭引用检测后,重复引用对象时就不会被$ref代替,但是在循环引用时也会导致StackOverflowError异常。
避免重复引用序列化时显示$ref
在编码时,使用新对象为集合或对象赋值,而非使用同一对象
不要在多处引用同一个对象,这可以说是一种java编码规范,需要时刻注意。不要关闭FastJson的引用检测来避免显示$ref
引用检测是FastJson提供的一种避免运行时异常的优良机制,如果为了避免在重复引用时显示$ref而关闭它,会有很大可能导致循环引用时发生StackOverflowError异常。这也是FastJson默认开启引用检测的原因。
避免重复/循环引用的正确姿势
List&Object& list = new ArrayList&&();
Object obj = new Object();
list.add(obj);
Object newObj = new Object();
BeansUtils.copy(obj, newObj);
list.add(obj);
循环引用这种逻辑本身就不合理,需要在编码时注意避免,这是逻辑错误而非编码技巧。
【FastJSON】解决FastJson中“$ref 循环引用”的问题
【FastJSON】解决FastJson中“$ref 循环引用”的问题&三种方式对应不同需求&
JSON工具学习记录--FastJSON循环引用问题
fastjson把对象转化成json避免$ref
解决fastjson循环引用问题(死循环)
spring mvc json循环引用
FastJson循环引用问题
json数据避免$ref 循环引用
FastJson禁用循环引用检测
fastjson使用(七)
没有更多推荐了,[IgnoreDataMember]:json序列化循环引用的问题
An exception has occurred while using the formatter 'JsonMediaTypeFormatter' to generate sample for media type 'application/json'. Exception message: Self referencing loop detected for property '******' with type '******'. Path '[0].******[0]'.
找到相应的属性,添加attribute:[IgnoreDataMember]
(System.Runtime.Serialization.dll)
------特殊情况分割线-------
还有时候会出现特殊情况,即使标记以上的attribute也不能解决
具体错误为: Newtonsoft.Json.JsonSerializationException 时 Self referencing loop detected for property *****
可以在web api的config中(WebApiConfig.cs)添加一下代码,用以过滤掉此问题
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.I
Newtonsoft.Json转换强类型DataTable错误:Self referencing loop detected with type ......
JSON.NET Error Self referencing loop detected for type
页面的循环引用与监听事件的添加与删除,页面逻辑管理
解决让部分属性不可被序列化(序列化循环引用时)
EF提示“序列化类型为XXX的对象时检测到循环引用”
没有更多推荐了,超高性能的json序列化之MVC中使用Json.Net - xiaoafei1991 - 博客园
先不废话,直接上代码
Asp.net MVC自带Json序列化
1 /// &summary&
2 /// 加载组件列表
3 /// &/summary&
4 /// &param name="departmentId"&作业部/厂&/param&
5 /// &param name="unitId"&组件Id&/param&
6 /// &param name="tag"&标签号&/param&
7 /// &param name="pageIndex"&当前页码&/param&
8 /// &param name="pageSize"&每页条数&/param&
9 /// &returns&返回组件json数据&/returns&
10 public JsonResult ListCom(long departmentId, IEnumberable&long& unitIds, string tag, int pageIndex, int pageSize)
var dataEntity = LdarService.ListCom(unitIds, tag, pageIndex + 1, pageSize);
var dataModel = new Page&LdComModel& {Total = dataEntity.Total};
var data =
dataModel.DataList =
dataEntity.DataList.Select(model =& Builder.Builder.Convert&LdComModel&(new object[] {model}));//Entity转ViewModel
dataModel.DataList =
return Json(new {
msg = CommonModelBuilder.BuildQuerySuccessMessage("组件信息维护", (int) dataModel.Total),
data = dataModel.DataList,
total = dataModel.Total
显示到前台界面
接收到的报文中有很多导航属性,前台并不需要这些属性.
LdComModel类中关联了很多外表,也就是导航属性,导航也被序列化,这样不科学,会将所有属性包括导航属性都序列化,还可能会造成循环引用,导致报错。我只想序列需要的字段,这时可以手写一个匿名类
1 var data=new {
model.AreaName,
model.AreaId,
这么写字段少还好,字段多就很不爽吧。
这时我们可以用Json.Net序列化,首先引用newtonsoft.json.dll,使用nuget引用比较方便。在不想序列化的属性上打上[JsonIgnore]特性,序列化就会被忽略。
LdComModel类中的部分代码
1 /// &summary&
2 /// 分区
3 /// &/summary&
4 [JsonIgnore]
5 public LdAreaModel LdAreaModel { get; set; }
7 /// &summary&
8 /// 区域名称
9 /// &/summary&
10 public string AreaName
return LdAreaModel.LdarAreaN
使用JsonNet序列化
1 /// &summary&
2 /// 加载组件列表
3 /// &/summary&
4 /// &param name="departmentId"&作业部/厂&/param&
5 /// &param name="unitId"&组件Id&/param&
6 /// &param name="tag"&标签号&/param&
7 /// &param name="pageIndex"&当前页码&/param&
8 /// &param name="pageSize"&每页条数&/param&
9 /// &returns&返回组件json数据&/returns&
10 public JsonResult ListCom(long departmentId, IEnumberable&long& unitIds, string tag, int pageIndex, int pageSize)
var dataEntity = LdarService.ListCom(unitIds, tag, pageIndex + 1, pageSize);
var dataModel = new Page&LdComModel& {Total = dataEntity.Total};
var data =
dataModel.DataList =
dataEntity.DataList.Select(model =& Builder.Builder.Convert&LdComModel&(new object[] {model}));//Entity转ViewModel
dataModel.DataList =
var result = new JsonNetResult()
Data = new
msg = CommonModelBuilder.BuildQuerySuccessMessage("组件信息维护", (int) dataModel.Total),
data = dataModel.DataList,
total = dataModel.Total
这时返回到前台的json中没有多余的导航属性.
导航属性没有被序列化,速度也快了很多。
这样写,虽然可以实现功能,很每次都要new一个JsonNetResult对象,写起来很是不爽,能不能给Controller写个扩展方法,像Json(...)一样直接写JsonNet(...)?
Controller中Json(...)方法的部分源码
/// &summary&
/// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 的 &see cref="T:System.Web.Mvc.JsonResult"/& 对象。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的 JSON 结果对象。在执行此方法所准备的结果对象时,ASP.NET MVC 框架会将该对象写入响应。
/// &/returns&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
protected internal JsonResult Json(object data)
return this.Json(data, (string) null, (Encoding) null, JsonRequestBehavior.DenyGet);
14 // &summary&
/// 创建 &see cref="T:System.Web.Mvc.JsonResult"/& 对象,该对象使用内容类型、内容编码和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的结果对象。
/// &/returns&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&&param name="contentType"&内容类型(MIME 类型)。&/param&&param name="contentEncoding"&内容编码。&/param&&param name="behavior"&JSON 请求行为&/param&
protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
return new JsonResult()
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior
我们可以仿照Controller中的源码,自己给Controller写个扩展方法JsonNet(...)
2 using System.Collections.G
3 using System.L
4 using System.T
5 using System.W
7 namespace System.Web.Mvc
public static class ControllerExt
/// &summary&
/// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 的 &see cref="T:System.Web.Mvc.JsonNetResult"/& 对象。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的 JSON 结果对象。在执行此方法所准备的结果对象时,ASP.NET MVC 框架会将该对象写入响应。
/// &/returns&
/// &param name="controller"&控件器&/param&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
public static JsonNetResult JsonNet(this Controller controller, object data)
return JsonNet(data, (string) null, (Encoding) null, JsonRequestBehavior.DenyGet);
/// &summary&
/// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式的 &see cref="T:System.Web.Mvc.JsonNetResult"/& 对象。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的 JSON 结果对象。
/// &/returns&
/// &param name="controller"&控件器&/param&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
/// &param name="contentType"&内容类型(MIME 类型)。&/param&
public static JsonNetResult JsonNet(this Controller controller, object data, string contentType)
return JsonNet(data, contentType, (Encoding) null, JsonRequestBehavior.DenyGet);
/// &summary&
/// 创建一个将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式的 &see cref="T:System.Web.Mvc.JsonNetResult"/& 对象。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的 JSON 结果对象。
/// &/returns&
/// &param name="controller"&控件器&/param&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
/// &param name="contentType"&内容类型(MIME 类型)。&/param&
/// &param name="contentEncoding"&内容编码。&/param&
public static JsonNetResult JsonNet(this Controller controller, object data, string contentType,
Encoding contentEncoding)
return JsonNet(data, contentType, contentEncoding, JsonRequestBehavior.DenyGet);
/// &summary&
/// 创建 &see cref="T:System.Web.Mvc.JsonNetResult"/& 对象,该对象使用指定 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的结果对象。
/// &/returns&
/// &param name="controller"&控件器&/param&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
/// &param name="behavior"&JSON 请求行为。&/param&
public static JsonNetResult JsonNet(this Controller controller, object data, JsonRequestBehavior behavior)
return JsonNet(data, (string) null, (Encoding) null, behavior);
/// &summary&
/// 创建 &see cref="T:System.Web.Mvc.JsonNetResult"/& 对象,该对象使用指定内容类型和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的结果对象。
/// &/returns&
/// &param name="controller"&控件器&/param&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
/// &param name="contentType"&内容类型(MIME 类型)。&/param&
/// &param name="behavior"&JSON 请求行为&/param&
public static JsonNetResult JsonNet(this Controller controller, object data, string contentType,
JsonRequestBehavior behavior)
return JsonNet(data, contentType, (Encoding) null, behavior);
/// &summary&
/// 创建 &see cref="T:System.Web.Mvc.JsonNetResult"/& 对象,该对象使用内容类型、内容编码和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
/// &/summary&
/// &returns&
/// 将指定对象序列化为 JSON 格式的结果对象。
/// &/returns&
/// &param name="controller"&控件器&/param&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
/// &param name="contentType"&内容类型(MIME 类型)。&/param&
/// &param name="contentEncoding"&内容编码。&/param&&param name="behavior"&JSON 请求行为&/param&
public static JsonNetResult JsonNet(this Controller controller, object data, string contentType,
Encoding contentEncoding, JsonRequestBehavior behavior)
return JsonNet(data, contentType, contentEncoding, behavior);
/// &summary&
/// 创建 &see cref="T:System.Web.Mvc.JsonNetResult"/& 对象,该对象使用内容类型、内容编码和 JSON 请求行为将指定对象序列化为 JavaScript 对象表示法 (JSON) 格式。
/// &/summary&
/// &param name="data"&要序列化的 JavaScript 对象图。&/param&
/// &param name="contentType"&内容类型(MIME 类型)。&/param&
/// &param name="contentEncoding"&内容编码。&/param&
/// &param name="behavior"&&/param&
/// &returns&JSON 请求行为&/returns&
private static JsonNetResult JsonNet(object data, string contentType, Encoding contentEncoding,
JsonRequestBehavior behavior)
return new JsonNetResult()
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior
Controller扩展方法
写个JsonNetResult类,继承自JsonResult,重写ExecuteResult()方法,内部使用JsonNet来序列化。
1 using System.T
2 using Newtonsoft.J
4 namespace System.Web.Mvc
public class JsonNetResult : JsonResult
public Encoding ContentEncoding { get; set; }
public string ContentType { get; set; }
public object Data { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult()
SerializerSettings = new JsonSerializerSettings();
public override void ExecuteResult(ControllerContext context)
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.R
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentE
if (Data != null)
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
JsonSerializer serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
JsonNetResult
封装后的JsonNet序列化
1 /// &summary&
2 /// 加载组件列表
3 /// &/summary&
4 /// &param name="departmentId"&作业部/厂&/param&
5 /// &param name="unitId"&组件Id&/param&
6 /// &param name="tag"&标签号&/param&
7 /// &param name="pageIndex"&当前页码&/param&
8 /// &param name="pageSize"&每页条数&/param&
9 /// &returns&返回组件json数据&/returns&
10 public JsonNetResult ListCom(long departmentId, IEnumberable&long& unitIds, string tag, int pageIndex, int pageSize)
var dataEntity = LdarService.ListCom(listUnitId, tag, pageIndex + 1, pageSize);
var dataModel = new Page&LdComModel& {Total = dataEntity.Total};
var data =
dataModel.DataList =
dataEntity.DataList.Select(model =& Builder.Builder.Convert&LdComModel&(new object[] {model}));//Entity转ViewModel
dataModel.DataList =
return this.JsonNet(new
msg = CommonModelBuilder.BuildQuerySuccessMessage("组件信息维护", (int) dataModel.Total),
data = dataModel.DataList,
total = dataModel.Total
&这样调用起来跟自带的Json(...)一样,非常方便。
由于时间关系,博客就先写到这里。不足及错误之处,敬请批评指正。

我要回帖

更多关于 excel循环引用如何解决 的文章

 

随机推荐