【问题标题】:Using JSON.NET to return ActionResult [duplicate]使用 JSON.NET 返回 ActionResult [重复]
【发布时间】:2014-06-14 10:09:04
【问题描述】:

我正在尝试编写一个将序列化模型并返回 JSON 结果的 C# 方法。这是我的代码:

    public ActionResult Read([DataSourceRequest] DataSourceRequest request)
    {
        var items = db.Words.Take(1).ToList();
        JsonSerializerSettings jsSettings = new JsonSerializerSettings();
        jsSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        var converted = JsonConvert.SerializeObject(items, null, jsSettings);
        return Json(converted, JsonRequestBehavior.AllowGet);
    }

当我在 Chrome 中转到 Words/Read 时,我得到了以下 JSON 结果:

"[{\"WordId\":1,\"Rank\":1,\"PartOfSpeech\":\"article\",\"Image\":\"Upload/29/1/Capture1.PNG\",\"FrequencyNumber\":\"22038615\",\"Article\":null,\"ClarificationText\":null,\"WordName\":\"the | article\",\"MasterId\":0,\"SoundFileUrl\":\"/UploadSound/7fd752a6-97ef-4a99-b324-a160295b8ac4/1/sixty_vocab_click_button.mp3\",\"LangId\":1,\"CatId\":null,\"IsActive\":false}

我认为 \" 转义引号是双重序列化对象时出现的问题。来自其他问题: WCF JSON output is getting unwanted quotes & backslashes added

看起来我对我的对象进行了双重序列化,因为我首先使用 JSON.NET 进行序列化,然后将结果传递给 Json() 函数。我需要手动序列化以避免引用循环,但我认为我的视图需要一个 ActionResult。

如何在此处返回 ActionResult?我需要,还是可以只返回一个字符串?

【问题讨论】:

  • 在 javascript 返回时我只做 JSON.parse(message);.
  • 你的意思是使用 Javascript 来解析 /"s?我正在使用 Razor HTML 帮助程序来处理特定的包,所以我不知道如何让它工作..跨度>

标签: c# serialization json.net asp.net-mvc-5


【解决方案1】:

我发现了一个类似的 stackoverflow 问题: Json.Net And ActionResult

那里的答案建议使用

return Content( converted, "application/json" );

这似乎适用于我非常简单的页面。

【讨论】:

  • IMO 最佳答案。简单,完全按照要求做。
  • 如果你检查标题,你会看到你可能有text/html作为内容类型。
  • 迄今为止最简单的解决方案。这正是它所需要的。
  • 基于 hubatish 的回答: public abstract class ControllerBase : Controller { protected const string JsonEncoding = "application/json; charset=utf-8"; protected ContentResult JsonNetResult(object result) { string json = JsonConvert.SerializeObject(result);返回内容(json,JsonEncoding); } }
  • @Dementic 也许在 4 年内发生了一些变化,但使用此答案中的语法,我的响应标题显示 content-type: application/json
【解决方案2】:

与其使用 JSON.NET 进行序列化,然后调用 Json(),不如重写控制器(或者可能是基础控制器以增强其可重用性)中的 Json() 方法?

这是从 blog post 中提取的。

在您的控制器(或基本控制器)中:

protected override JsonResult Json(
        object data,
        string contentType,
        System.Text.Encoding contentEncoding,
        JsonRequestBehavior behavior)
{
    return new JsonNetResult
    {
        Data = data,
        ContentType = contentType,
        ContentEncoding = contentEncoding,
        JsonRequestBehavior = behavior
    };
}

以及 JsonNetResult 的定义:

public class JsonNetResult : JsonResult
{
    public JsonNetResult()
    {
        Settings = new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        };
    }

    public JsonSerializerSettings Settings { get; private set; }

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


        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType =
            string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;

        if (this.ContentEncoding != null)
            response.ContentEncoding = this.ContentEncoding;
        if (this.Data == null)
            return;

        var scriptSerializer = JsonSerializer.Create(this.Settings);

        using (var sw = new StringWriter())
        {
            scriptSerializer.Serialize(sw, this.Data);
            response.Write(sw.ToString());
        }
    }
}

通过这样做,当您在控制器中调用 Json() 时,您将自动获得所需的 JSON.NET 序列化。

【讨论】:

  • 酷。这很方便。另外,我在想这仍然可以让我通过 JSONRequestBehavior.AllowGet,但它似乎并不能正常工作。
  • 要使其正常工作,您需要向Json() 添加覆盖,以传递其他参数的默认值。这是默认实现所做的。
  • 只需为contentTypecontentEncoding 传入null,您将获得与默认实现相同的结果。否则为Json() 添加一个只接受databehavior 的重载,并为contentTypecontentEncoding 提供空值,然后使用我的答案中的所有参数调用实现。
  • JsonNetResult 对 AllowGet 的执行对于应用于方法的属性似乎是多余的 - 令我惊讶的是,当我已经拥有 AcceptVerbsAttribute 时,我不得不重复启用 AllowGet。需要了解如何从 ControllerContext 中读取 AcceptVerbsAttribute。
  • 反响很好。我的问题是关于最后一部分:将所有内容序列化到 StringWriter 然后写入 HTTP 响应更好,还是直接写入输出流更有效? using (var sw = new StreamWriter(response.OutputStream, response.ContentEncoding)) { scriptSerializer.Serialize(sw, Data); sw.Flush(); }
猜你喜欢
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-08
  • 2023-03-20
相关资源
最近更新 更多