65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET MVC - SerializedDataResult

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (3投票s)

2011年2月10日

CPOL

3分钟阅读

viewsIcon

27875

downloadIcon

205

创建一个自定义的 ASP.NET MVC ActionResult,以 JSON 或 XML 格式返回序列化的数据

更新 - 2012年5月 

此代码已被 ASP.NET MVC 4 Web API 淘汰,后者可以完成此处的所有操作,并且功能更强大。   

引言

我最近开发了一个 ASP.NET MVC 应用程序,该应用程序使用 jQuery 调用 JsonResult 控制器方法并在浏览器中显示数据。当应用程序完成后,我意识到我的 JsonResult 控制器方法实际上构成了一个 API,允许其他应用程序查询我应用程序后面的数据,而我这边无需做任何额外的工作。这是一个“意外的 API”,但运行良好。然后,我收到一个请求,要求将数据作为 XML 而不是 JSON 返回,这就是我在 MVC 遇到一些障碍的地方。

ASP.NET MVC 有几种内置的 ActionResult 类型,包括一种数据序列化类型:JsonResult。 虽然 JsonResult 很棒,但它没有解决以其他序列化格式(尤其是 XML)返回数据的需求。如果可以编写一个控制器方法,该方法可以根据用户的请求返回 JSON 或 XML,那就太好了。有些人通过在控制器方法中进行分支来实现这一点,如果条件为 X 则返回 JsonResult ,如果条件为 Y 则返回 XmlResult (来自 MvcContrib)。其他人创建了自定义的 ActionFilter,它们检测用户请求中的“接受类型”标头,并根据该标头决定返回什么。

这两种解决方案对我来说都不是特别有吸引力。在第一种情况下,基于控制器方法内的数据格式参数或标头值进行分支看起来有点难看 - 您会为每个返回序列化数据的控制器方法重复此 if 逻辑,并且此逻辑可能变得非常复杂,并且使您的控制器难以理解。在第二种情况下,为返回 JSON 数据的 JsonResult 类创建 ActionFilter 似乎在逻辑上是不正确的,但当需要更高级的功能时,切换到 ActionFilter - 为什么不使用另一个 ActionResult 类型来适应现有的模式,但更灵活呢?最后,在两种情况下,控制器签名都使用基本 ActionFilter 类型,而不是更具体的(并且更可取的)JsonResult XmlResult 类型。

为了满足我的需求,我创建了一个名为 SerializedDataResult 的类,该类可以根据控制器方法中的显式指令或通过请求查询字符串、表单或标头的隐式指令,以 JSON 或 XML 格式返回数据。还有一个辅助方法,它实现为控制器的扩展,类似于用于创建 JsonResult 实例的 Json 方法。该代码基于 JsonResult 类(来自 开源 ASP.NET MVC 3 库,感谢微软!)和 XmlResult 类(来自 MvcContrib 项目),并受到使用 ActionFilter 解决此问题的各种尝试的启发。

Using the Code

使用此代码有两种基本场景。在第一种情况下,您知道要以哪种格式返回数据,并且您可以使用 SerializedDataFormat enum 告诉 SerializedDataResult

// data will be returned in JSON format
public SerializedDataFormat JsonQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(
		svc.GetQuote(code),
		SerializedDataFormat.Json,
		null, null, null,
		SerializedDataRequestBehavior.AllowGet);
}

// data will be returned in XML format
public SerializedDataResult XmlQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(
		svc.GetQuote(code),
		SerializedDataFormat.Xml,
		null, null, null,
		SerializedDataRequestBehavior.AllowGet);
}

在第二种情况下,请求用户决定以哪种格式返回数据。他们可以在请求的查询字符串、表单或接受类型标头中执行此操作。

// data will be returned in the format requested by the user, 
// or JSON if it can't be determined what format the user wants
public SerializedDataResult AutoQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(svc.GetQuote(code), 
		SerializedDataRequestBehavior.AllowGet);
}

SerializedDataResult 将首先在查询字符串和表单中检查一个名为“format”的字段(这是可配置的)。该字段的值必须为“xml”或“json”。如果它在查询字符串或表单中找不到格式字段,它将检查接受类型标头的值以获取已识别的类型,特别是“text/xml”和“application/json”。如果找到这些类型之一,它会执行显而易见的操作,并以相应的格式返回数据。最后,如果它无法确定请求用户想要的类型,则默认为 JSON。

例如。http://www.example.com/StockMarket/Quote/ABC?format=xml - 这将以 XML 格式返回报价

// a more complex call to the Serialize helper method
// data will be returned in the format requested by the user, 
// or JSON if it can't be determined what format the user wants
public SerializedDataResult ComplexQuote(string code)
{
	var svc = new StockMarketService();
	return this.Serialize(
		svc.GetQuote(code),
		SerializedDataFormat.Auto,
		"dataformat", // request querystring / form field containing format
		"application/quoteserver", // content-type to put in response header
		Encoding.Unicode, // encoding type for response
		SerializedDataRequestBehavior.AllowGet);
}

关注点

ActionResult 使用 JsonResult 中的 RequestBehavior.AllowGet/DenyGet 模式,Phil Haack 在 这篇文章 中对此进行了说明。我从 JsonResult 代码中提取了此逻辑。

历史

  • 2010年2月10日 - 版本 1
  • 2010年2月11日 - 版本 1.1 - 向项目中添加了一些单元测试,从示例中删除了 CSS 和 JavaScript 文件,更正了 XML 结果的内容编码
© . All rights reserved.