MVC:如何将字符串返回为JSON


70

为了使进度报告过程更加可靠,并将其与请求/响应分离,我正在Windows Service中执行处理,并将预期的响应持久化到文件中。当客户端开始轮询更新时,其目的是控制器以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;
    }
}

您不仅可以返回字符串,还需要将返回类型更改为字符串。
RubbleFord 2012年

您正在使用什么进行Ajax调用(jQuery,custom,dojo)?您可以提供该代码吗?
保罗

我看不到您path在控制器操作的任何地方使用此变量。您在哪里读取文件的内容?您要做的就是返回带有Properties.Settings.Default.EmptyBatchSearchUpdate属性内容的JSON 。您是否还知道在另一个线程写入文件时无法读取文件?至少这不能以安全的方式发生。您可能很快就会遇到比赛状况。因此,我认为您的设计从一开始就是有缺陷的。
Darin Dimitrov

@Paul我正在使用Ajax,一分钟后将其发布。上面的代码已被编辑,我将在几秒钟内对其进行更改。在提琴手返回中看到的返回值准确地表示我尝试响应的JSON对象的正确转义的C#字符串。
CodeWarrior 2012年

1
是的,我已经遇到了问题,并已采取措施在Windows Service中阻止它。谢谢!
CodeWarrior 2012年

Answers:


131

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

不过,您传递给控制器​​的Json方法的是一个JSON格式的字符串对象,因此它将字符串对象“序列化”为JSON,这就是HTTP响应的内容被双引号引起来的原因(I' m假设是问题所在)。

我想您可以考虑使用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方法,但是缺点是您将反序列化然后重新序列化数据,这可能是不必要的为了您的目的。


4
+1:您还需要将结果的ContentType属性设置为“ application / json”,因为这是JsonResult自动执行的操作。
StriplingWarrior 2012年

@StriplingWarrior好点,我将更新代码示例以使用其他Content方法重载。
Wily博士的学徒

值得注意的Content是,返回的ContentResult地方Json正在返回JsonResult
Shoter

44

您只需要返回标准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);
}

虽然它的最大好处是可重复使用。我只需要一个响应。但是,如果将来在其他地方需要它,我将完全走这个答案的路线。
CodeWarrior 2015年

3

是的,没有更多问题,可以避免使用原始字符串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
        };
    } 

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


2

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

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

在JavaScript中:

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

感谢您提供新的答案,但这并不完全适合原始问题。我有要返回的预生成的JSON数据,而不是我想要表示为JSON对象的字符串值的东西。另外,请注意,在这个问题中,我处于显式标记为HTTP Post的操作中。AllowGet对此无能为力。
CodeWarrior

0

这里的所有答案都提供了良好且有效的代码。但是有人会对它们全部ContentType用作返回类型而不是返回类型感到不满意JsonResult

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

我从原始类JsonResult和创建的JsonStringResult类中复制了大多数代码,该类将传递的字符串作为返回application/json。此类的代码如下

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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.