【问题标题】:MVC: How to Return a String as JSONMVC:如何将字符串返回为 JSON
【发布时间】:2012-03-19 20:50:08
【问题描述】:

为了使进度报告过程更加可靠并将其与请求/响应分离,我正在 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;
    }
}

【问题讨论】:

  • 你不能只返回字符串,你需要将返回类型更改为字符串。
  • 您使用什么来进行 Ajax 调用(jQuery、自定义、dojo)?你能提供那个代码吗?
  • 我没有看到您在控制器操作中的任何地方使用此 path 变量。你在哪里读取文件的内容?您所要做的就是返回一个包含 Properties.Settings.Default.EmptyBatchSearchUpdate 属性内容的 JSON。您还知道当另一个线程正在写入文件时您无法读取文件吗?至少这不能以安全的方式发生。您可能很快就会遇到竞争状况。所以我认为你的设计从一开始就有缺陷。
  • @Paul 我正在使用 Ajax,我会在一分钟内发布。上面的代码已编辑,我将在几秒钟内更改它。在提琴手返回中看到的返回值准确地代表了我试图响应的 JSON 对象的正确转义的 C# 字符串。
  • 是的,我已经遇到了这方面的问题,并已采取措施在 Windows 服务中阻止它。谢谢!

标签: asp.net-mvc json


【解决方案1】:

我认为,问题在于 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 方法,但缺点是您将反序列化然后重新序列化数据,这对您的目的而言可能是不必要的。

【讨论】:

  • +1:您还需要将结果的 ContentType 属性设置为“application/json”,因为这是 JsonResult 自动执行的操作。
  • @StriplingWarrior 好点,我将更新我的代码示例以使用其他 Content 方法重载。
  • 值得注意的是Content正在返回ContentResult,而Json正在返回JsonResult
  • 还有一个带编码的签名:return this.Content(returntext, "application/json", System.Text.Encoding.UTF8);
【解决方案2】:

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

【讨论】:

  • 确实如此,尽管它最大的好处是可重复使用。我只需要一个响应。但是,如果将来我在其他地方需要它,我会完全走这个答案的路线。
【解决方案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
        };
    } 

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

【讨论】:

    【解决方案4】:

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

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

    在 JavaScript 中:

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

    【讨论】:

    • 感谢您提供新答案,但这并不真正适合原始问题。我有预生成的想要返回的 JSON 数据,而不是我想要表示为 JSON 对象的字符串值的东西。另外,请注意,在问题中,我处于一个明确标记为 HTTP Post 的操作中。 AllowGet 不会为此做任何事情。
    【解决方案5】:

    这里的所有答案都提供了良好且有效的代码。但是有人会不满意他们都使用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);
    

    【讨论】:

      猜你喜欢
      • 2020-03-30
      • 2010-12-04
      • 2015-07-24
      • 1970-01-01
      • 2021-08-14
      • 2013-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多