使用Json.Net在MVC中返回未转义的Json

我在使用Json.Net在MVC项目中找出如何返回未转义的Json时遇到了令人惊讶的麻烦。 它完全暗指我,但我确定我错过了一些简单的东西……

到目前为止,我序列化了一个基本对象,并让Json.Net对其进行序列化:

public JsonResult GetTimelineJson() { var result = new MyGraph([some data...]); return Json(JsonConvert.SerializeObject(result), JsonRequestBehavior.AllowGet); } 

结果:

 "{\r\n \"id\": \"myGraph\",\r\n \"title\": \"Graph title\",\r\n [...] 

任何将它包装成HtmlString等的尝试都会导致在线上传递一个空集(尽管调试点显示它正确地未转义)。 我已经检查过HTTP标头中是否正确设置了内容类型。

任何和所有的帮助表示赞赏,谢谢。

该对象已经由Json.NET序列化,当您将其传递给Json()时,它会被编码两次。 如果必须使用Json.NET而不是内置编码器,那么理想的处理方法是创建自定义ActionResult接受对象并在内部调用Json.net来序列化对象并将其作为application / json结果返回。

编辑

此代码用于上述解决方案。 这是未经测试的,但应该有效。

 public class JsonDotNetResult : ActionResult { private object _obj { get; set; } public JsonDotNetResult(object obj) { _obj = obj; } public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.AddHeader("content-type", "application/json"); context.HttpContext.Response.Write(JsonConvert.SerializeObject(_obj)); } } 

并在你的控制器中只做:

 return new JsonDotNetResult(result); 

你也可以这样做

 public ActionResult GetTimelineJson() { var result = new MyGraph([some data...]); return Content(JsonConvert.SerializeObject(result), "application/json"); } 

请注意,您应该将返回类型从JsonResult更改为ActionResult

你是Jsoning它两次, Json方法是json序列化你已经转换的字符串。 如果要使用JsonConvert,则将其直接写入响应流。

我对我的新课程做了一些改动,使unit testing变得更容易:

 public class JsonDotNetResult : ActionResult { public JsonDotNetResult(object data) { Data = data; } //Name the property Data and make the getter public public object Data { get; private set; } public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.AddHeader("content-type", "application/json"); context.HttpContext.Response.Write(JsonConvert.SerializeObject(Data)); } } 

}

这更类似于System.Web.Mvc中的JsonResult,并允许我使用通用方法进行unit testing…

System.Web.Mvc.JsonResult

unit testing助手:

 public static TReturn GetDataFromJsonResult(this ActionResult result) where TJsonType : ActionResult { var jsonResult = (TJsonType)result; var data = jsonResult.GetType().GetProperty("Data").GetValue(jsonResult); return (TReturn)data; } 

unit testing示例:

 [TestMethod] public void ControllerMethod_WhenMethodCalled_ThenSomeRecordsAreReturned() { // arrange var records = new List { "Record1", "Record2" }; var expectedRecordCount = records.Count(); myService.Setup(x => x.GetRecordsFromDatabase()).Returns(records); // act var result = myController.GetRecords(); //Assuming this controller method returns JsonDotNetResult // assert var jsonResult = result.GetDataFromJsonResult>(); Assert.AreEqual(expectedRecordCount, jsonResult.Count()); } 

如果控制器返回正常的JsonResult,则可以更改此行:

  var jsonResult = result.GetDataFromJsonResult>();