前言

一般我们在开法 ASP.NET Web API 时,如果是使用 Entity Framework 技术来操作数据库的话,当两个 Entity 之间包含导览属性(Navigation Property)时,而当我们输出的格式为 JSON 对象时,会出现一个例外,错误讯息为:「'ObjectContent`1' 类型无法序列化内容类型 'application/json; charset=utf-8' 的回应主体。」,而小弟参考了 Will 保哥以及 Bruce 两位前辈的文章后,整理出两种小弟觉得比较可行的替代与解决方案。

了解问题

 

这张图里包含了两张数据表 Orders 与 Order_Details ,两者之间存在着一对多的关系,而预设 Entity Framework 会自动帮我们的关联数据表加入导览属性(Navigation Property),接着我们往下一张图看下去:

public IEnumerable<Orders> GetOrders()         {             return db.Orders;         }

这段程序代码为 ValuesController 里的一个 Function ,当我们请求时会返回 Orders 所有数据,但当我们输入网址 /api/Values/ 请求时却发生了这样的错误:

这个问题发生的原因为,当我们请求某个特定的 Enity 时会取出该 Entity 的所有属性内容,当然包夸了导览属性的数据,而究竟这个问题如何照成呢?以目前的案例来看,当我们取得 Orders 的资料时也会一并取得其导览属性,也就是 Order_Details 的所有数据,而在 Order_Details 里也包含着 Orders 的导览属性,所以又会在去取得 Orders 的数据....,这样两个实体之间不停的往返就会造成了无限循环,也是我们前面所说的循环参考的错误。

如何解决

方法一:

在开发 ASP.NET MVC 中,时常会用到部分类别(Partail Class)来为我们的数据域位加上验证属性,所以利用此特性来解决我们的问题,首先在 Model 数据夹底下新增两个档案分别为:OrdersMetadata.cs 、Order_DetailsMetadata.cs

01.OrdersMetadata.cs
02.  
03.    [MetadataType(typeof(OrderMD))]
04.    public partial class Order
05.    {
06.        public class OrderMD
07.        {
08.            [JsonIgnore()] // 需引用 using Newtonsoft.Json;
09.            public virtual ICollection<Order_details> Order_Details { get; set; }
10.        }
11.    }Order_DetailsMetadata.cs
12.  
13.    [MetadataType(typeof(Order_DetailsMD))]
14.    public partial class Order_Details
15.    {
16.        public class Order_DetailsMD
17.        {
18.            [JsonIgnore()]  // 需引用 using Newtonsoft.Json;
19.            public virtual Orders Orders { get; set; }
20.        }
21.    }

这边我们在在对应的导览属性上都加上 「JsonIgnore」的属性,来防止循环参考的问题发生,记得是有关联的两边都要加上「JsonIgnore」的属性。

方法二:

另外一种方法则是利用我们在开发 ASP.NET MVC 时常用到的 ViewModel 的概念,针对特定的页面或请求只返回特定的数据,所以这边我们能透过 DTO 方式来解决我们问题,首先我们先在 Model 底下新增一个 DTO.cs 档案: www.it165.net

DTO.cs

01.public class OrderDTO
02.{
03.    public int OrderID { get; set; }
04.    public string CustomerID { get; set; }
05.    public int? EmployeeID { get; set; }
06.    public DateTime? OrderDate { get; set; }
07.    public List<Order_detailsDTO> Order_Detail { get; set; }
08.}
09.public class Order_DetailsDTO
10.{
11.    public int OrderID { get; set; }
12.    public decimal UnitPrice { get; set; }
13.    public decimal Quantity { get; set; }
14.}

并且修改我们原本在 Web API Controller 里的 Function:

01.public IEnumerable<OrderDTO> GetOrders()
02.{
03.    NorthwindEntities db = new NorthwindEntities();
04.     
05.    return db.Orders.ToList().Select(p => new OrderDTO
06.    {
07.        CustomerID = p.CustomerID,
08.        EmployeeID = p.EmployeeID,
09.        OrderDate = p.OrderDate,
10.        OrderID = p.OrderID,
11.        Order_Detail = p.Order_Details.Select(x => new Order_DetailsDTO
12.        {
13.            OrderID = x.OrderID,
14.            Quantity = x.Quantity,
15.            UnitPrice = x.UnitPrice
16.        }).ToList()
17.    }); ;
18.}

总结

两种作法都能解决造成循环对象参考的问题,而在 Bruce 和 Will 保哥的文章都指出用第一种方法来解决此循环参考错误是最正确的作法,两种作法算是两种不同的出发点,所以该怎么用应该就是看各位读者如何应用了。

解决ASP.NET Web API Json对象循环参考错误的更多相关文章

  1. ASP.NET Web API 路由对象介绍

    ASP.NET Web API 路由对象介绍 前言 在ASP.NET.ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了 ...

  2. 解决asp.net web api时间datetime自动带上带上的T和毫秒的问题

    今天用asp.net web api写微信小程序的接口时遇到一个问题. 返回的model中的datetime类型的字段自动转换成了“2014-11-08T01:50:06:234”这样的字符串,带上的 ...

  3. [翻译]ASP.NET Web API 2 中的全局错误处理

    目录 已存在的选项 解决方案预览 设计原则 什么时候去用 方案详情 示例 附录: 基类详情 原文链接 Global Error Handling in ASP.NET Web API 2 由于翻译水平 ...

  4. ASP.NET Web Api返回对象类型为JSON还是XML

    在Umbraco平台上开发过程中,我用WebApi返回JSON result给前端 前端使用React调用这个web api来获取JSON result 我写的web api方法是返回JSON 类型的 ...

  5. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  6. ASP.NET Web API 2.0 统一响应格式

    传统实现 在搭建 Web API 服务的时候,针对客户端请求,我们一般都会自定义响应的 JSON 格式,比如: { "Data" : { "Id" : 100, ...

  7. ASP.NET Web API WebHost宿主环境中管道、路由

    ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境 ...

  8. ASP.NET Web API Selfhost宿主环境中管道、路由

    ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...

  9. ASP.NET Web API 管道模型

    ASP.NET Web API 管道模型 前言 ASP.NET Web API是一个独立的框架,也有着自己的一套消息处理管道,不管是在WebHost宿主环境还是在SelfHost宿主环境请求和响应都是 ...

随机推荐

  1. 日期格式化标签<fmt:formatDate>&<fmt:setTimeZone>时区标签的使用demo

    日期格式化标签<fmt:formatDate>&<fmt:setTimeZone>时区标签的使用demo <%@ page contentType="t ...

  2. Java学习之道:空指针错误求解救????????????

    运行下面这个主方法红色代码的地方就报如下错: https://api.weibo.com/2/users/show.json?access_token=2.00szM9cCc4R_EC6ebcf150 ...

  3. SWT的ListVierer的使用

    package com.test; import java.util.ArrayList; import java.util.List; import model.People; import org ...

  4. atitit查询表改动表字段没反应--解锁锁定的表

    atitit查询表改动表字段没反应--解锁锁定的表 查询表改动表字段没反应 要是使用gui 没反应,最好使用cmd 方式,不卉不个gui 锁上.. ALTER TABLE t_mb_awardweix ...

  5. 《Linux设备驱动开发具体解释(第3版)》进展同步更新

    本博实时更新<Linux设备驱动开发具体解释(第3版)>的最新进展. 2015.2.26 差点儿完毕初稿. 本书已经rebase到开发中的Linux 4.0内核,案例多数基于多核CORTE ...

  6. 在阿里云上布置git server

    前言 东莞,晴,26至32度. 一直以为都是使用SVN Server作为私用的版本号控制器.随着Git的大行其道.近期由于项目须要,也试着在阿里云上部署Git Server.这里由于团队人员少.我採用 ...

  7. 隐马尔科夫模型(HMM)及事实上现

    马尔科夫模型 马尔科夫模型是单重随机过程,是一个2元组:(S,A). 当中S是状态集合,A是状态转移矩阵. 仅仅用状态转移来描写叙述随机过程. 马尔科夫模型的2个如果 有限历史性如果:t+l时刻系统状 ...

  8. windows phone (16) UI变换 下

    原文:windows phone (16) UI变换 下 上一篇中说到四个变换类,都是比较简单的,这里要说到四个变换类,分别为: MatrixTransfrom矩阵变换,一句标准矩阵表示的变换 Tra ...

  9. python学习笔记之六:更加抽象

    Python被称为面向对象的语言,创建自己的对象是python非常核心的概念.这里会介绍如何创建对象,以及多态,封装,方法,特性,超类以及继承的概念. 一. 对象的魔力 面向对象程序设计中的术语 对象 ...

  10. android EditText的美化

    今天要做一个页面,有EditText,于是就搞起了它的美化. EditText的美化,我的第一反应是,在EditText的左边设置显示一张图片,这样会比較好看. 设置左边显示图片的属性为:androi ...