MVC: 如何返回 JSON 格式的字符串

为了使进度报告过程更加可靠,并使其与请求/响应分离,我在 Windows 服务中执行处理,并将预期的响应持久化到一个文件中。当客户端开始轮询更新时,目的是控制器以 JSON 字符串的形式返回文件的内容,不管它们是什么。

文件的内容被预序列化为 JSON。这是为了确保没有任何东西阻碍响应。不需要进行任何处理(除非将文件内容读入字符串并返回它)就可以获得响应。

我最初以为这会相当简单,但事实并非如此。

目前我的控制器方法如下:

控制员

更新

[HttpPost]
public JsonResult UpdateBatchSearchMembers()
{
string path = Properties.Settings.Default.ResponsePath;
string returntext;
if (!System.IO.File.Exists(path))
returntext = Properties.Settings.Default.EmptyBatchSearchUpdate;
else
returntext = System.IO.File.ReadAllText(path);


return this.Json(returntext);
}

Fiddler 把这个作为原始反应返回

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 19 Mar 2012 20:30:05 GMT
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 3.0
Cache-Control: private
Content-Type: application/json; charset=utf-8
Content-Length: 81
Connection: Close


"{\"StopPolling\":false,\"BatchSearchProgressReports\":[],\"MemberStatuses\":[]}"

AJAX

更新

下面的内容可能稍后会更改,但是目前这种方法在我生成响应类并像正常人一样将其返回为 JSON 时仍然有效。

this.CheckForUpdate = function () {
var parent = this;


if (this.BatchSearchId != null && WorkflowState.SelectedSearchList != "") {
showAjaxLoader = false;
if (progressPending != true) {
progressPending = true;
$.ajax({
url: WorkflowState.UpdateBatchLink + "?SearchListID=" + WorkflowState.SelectedSearchList,
type: 'POST',
contentType: 'application/json; charset=utf-8',
cache: false,
success: function (data) {
for (var i = 0; i < data.MemberStatuses.length; i++) {
var response = data.MemberStatuses[i];
parent.UpdateCellStatus(response);
}
if (data.StopPolling = true) {
parent.StopPullingForUpdates();
}
showAjaxLoader = true;
}
});
progressPending = false;
}
}
124582 次浏览

我认为,问题在于 Json 操作结果旨在获取一个对象(您的模型)并创建一个 HTTP 响应,其内容是来自您的模型对象的 JSON 格式的数据。

但是,您要传递给控制器的 JSON 方法的是一个 JSON 格式的 字符串对象,因此它将字符串对象“序列化”为 JSON,这就是 HTTP 响应的内容被双引号包围的原因(我假设这就是问题所在)。

我认为您可以考虑使用 Content 动作结果作为 Json 动作结果的替代,因为您实际上已经拥有了 HTTP 响应的原始内容。

return this.Content(returntext, "application/json");
// not sure off-hand if you should also specify "charset=utf-8" here,
//  or if that is done automatically

另一种方法是将服务的 JSON 结果反序列化为一个对象,然后将该对象传递给控制器的 JSON 方法,但是这样做的缺点是,您将反序列化数据,然后再重新序列化数据,这对您的目的来说可能是不必要的。

您只需返回标准 ContentResult 并将 ContentType 设置为“ application/json”。 您可以为它创建自定义 ActionResult:

public class JsonStringResult : ContentResult
{
public JsonStringResult(string json)
{
Content = json;
ContentType = "application/json";
}
}

然后返回它的实例:

[HttpPost]
public JsonResult UpdateBatchSearchMembers()
{
string returntext;
if (!System.IO.File.Exists(path))
returntext = Properties.Settings.Default.EmptyBatchSearchUpdate;
else
returntext = Properties.Settings.Default.ResponsePath;


return new JsonStringResult(returntext);
}

是的,没有进一步的问题,避免原始字符串 json 这是它。

    public ActionResult GetJson()
{
var json = System.IO.File.ReadAllText(
Server.MapPath(@"~/App_Data/content.json"));


return new ContentResult
{
Content = json,
ContentType = "application/json",
ContentEncoding = Encoding.UTF8
};
}

注意: 请注意,JsonResult的方法返回类型对我不起作用,因为 JsonResultContentResult都继承 ActionResult,但它们之间没有关系。

这里的所有答案都提供了良好的工作代码。但有些人会不满意,他们都使用 ContentType作为返回类型,而不是 JsonResult

不幸的是,JsonResult使用 JavaScriptSerializer时没有禁用它的选项。解决这个问题的最好方法是继承 JsonResult

我从原来的 JsonResult中复制了大部分代码,并创建了返回传递的字符串为 application/jsonJsonStringResult类。此类的代码如下

public class JsonStringResult : JsonResult
{
public JsonStringResult(string data)
{
JsonRequestBehavior = JsonRequestBehavior.DenyGet;
Data = data;
}


public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("Get request is not allowed!");
}


HttpResponseBase response = context.HttpContext.Response;


if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
response.Write(Data);
}
}
}

示例用法:

var json = JsonConvert.SerializeObject(data);
return new JsonStringResult(json);

在控制器中使用以下代码:

return Json(new { success = string }, JsonRequestBehavior.AllowGet);

以及 JavaScript:

success: function (data) {
var response = data.success;
....
}