解决ASP.NET Web API Json对象循环参考错误
前言
一般我们在开法 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对象循环参考错误的更多相关文章
- ASP.NET Web API 路由对象介绍
ASP.NET Web API 路由对象介绍 前言 在ASP.NET.ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了 ...
- 解决asp.net web api时间datetime自动带上带上的T和毫秒的问题
今天用asp.net web api写微信小程序的接口时遇到一个问题. 返回的model中的datetime类型的字段自动转换成了“2014-11-08T01:50:06:234”这样的字符串,带上的 ...
- [翻译]ASP.NET Web API 2 中的全局错误处理
目录 已存在的选项 解决方案预览 设计原则 什么时候去用 方案详情 示例 附录: 基类详情 原文链接 Global Error Handling in ASP.NET Web API 2 由于翻译水平 ...
- ASP.NET Web Api返回对象类型为JSON还是XML
在Umbraco平台上开发过程中,我用WebApi返回JSON result给前端 前端使用React调用这个web api来获取JSON result 我写的web api方法是返回JSON 类型的 ...
- ASP.NET Web API 框架研究 ASP.NET Web API 路由
ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...
- ASP.NET Web API 2.0 统一响应格式
传统实现 在搭建 Web API 服务的时候,针对客户端请求,我们一般都会自定义响应的 JSON 格式,比如: { "Data" : { "Id" : 100, ...
- ASP.NET Web API WebHost宿主环境中管道、路由
ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境 ...
- ASP.NET Web API Selfhost宿主环境中管道、路由
ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...
- ASP.NET Web API 管道模型
ASP.NET Web API 管道模型 前言 ASP.NET Web API是一个独立的框架,也有着自己的一套消息处理管道,不管是在WebHost宿主环境还是在SelfHost宿主环境请求和响应都是 ...
随机推荐
- android "Missing type parameter" 错误
近期在做android应该的时候出现这个问题,分析了一下日志,发现是在gosn解析的时候会出现,并且出现的时候非常诡异.于是去网上找相关资料. 发现这个问题还是比較常见的,原来是公布版本号和非正式公布 ...
- 求1e11以内的素数
有两种做法,一种是打表,另一种是直接求. 打表 将1e11每隔len(len=2000w)个数字统计一下该区间内素数的个数,比如cnt[1] 表示[1,len]以内有多少个素数,cnt[2]表示[le ...
- HashMap源码解读(转)
http://www.360doc.com/content/10/1214/22/573136_78188909.shtml 最近朋友推荐的一个很好的工作,又是面了2轮没通过,已经是好几次朋友内推没过 ...
- String的Split方法的用法与要注意事项
转自:http://shukuiyan.iteye.com/blog/1058672 之前在http://shukuiyan.iteye.com/blog/507915文中已经叙述过这个问题,但是最近 ...
- ecshop 全目录说明
ECShop 2.5.1 的结构图及各文件相应功能介绍 ECShop2.5.1_Beta upload 的目录 ┣ activity.php 活动列表 ...
- vim ctl+v批量添加/删除
vim编辑器---批量注释与反注释 在使用vim编写代码的时候,经常需要用到批量注释与反注释一段代码.下面简要介绍其操作. 方法一 块选择模式 插入注释: 用v进入virtual模式 用上下键选中需要 ...
- 漂亮的表格样式(使用CSS样式表控制表格样式)
根据WEB2.0风格,设计了几个表格样式,我希望你喜欢. WEB2.0推广使用div开放式布局.但并不是完全放弃使用形式,在数据表现形式而言是一个不错的选择. 本节将介绍如何使用现在CSS样式表来控制 ...
- 傻瓜式破解linux--rootpassword
破password的方法: 方法1.单用户模式改动 (表示进入到单用户模式) .按回车键.按b键启动.进入单用户模式,进行password改动.重新启动 init 5 口诀:e2e 空格1 回车b 开 ...
- Quartz.NET学习系列
Quartz.NET它是一个开源的任务调度引擎,对于周期性任务,持久性任务提供了很好的支持,并且支持持久性.集群等功能. 这是什么对我来说Quartz.NET学习记录: 源代码下载http://yun ...
- iOS相机去黑框
自己定义相机的时候,调用系统的相机,因为相机的分辨率,会出现短小的矩形框,总会出现黑色边框,例如以下图: 假设想实现全屏相机的话,这样做就能够了: CALayer *viewLayer = self. ...