使用 JSON.NET 返回 ActionResult

31 浏览
0 Comments

使用 JSON.NET 返回 ActionResult

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

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?我需要这样做吗,还是可以只返回一个字符串?

0
0 Comments

使用JSON.NET返回ActionResult的问题出现的原因是,想要替换控制器中默认的JSON序列化方式。解决方法是通过重写控制器中的Json()方法,并创建一个JsonNetResult类来自定义JSON序列化过程。

首先,在控制器(或基类控制器)中重写Json()方法,代码如下:

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进行序列化。

此外,还有一个问题是如何在调用Json()方法时传递JsonRequestBehavior.AllowGet参数。可以通过在Json()方法中添加重载来实现,该重载只接受data和behavior参数,并将contentType和contentEncoding参数设置为null,然后使用这些参数调用实现方法。代码如下:

protected override JsonResult Json(
    object data,
    JsonRequestBehavior behavior)
{
    return Json(data, null, null, behavior);
}

另外,某些情况下了在JsonNetResult类中对AllowGet的限制似乎与应用于方法的属性重复,他想知道如何从ControllerContext中读取AcceptVerbsAttribute。这个问题没有得到明确的回答。

还有一个人提到了关于序列化后直接写入输出流是否更高效的问题。他给出了一个使用StreamWriter和response.OutputStream来直接写入输出流的代码示例。但是,并没有给出明确的答案。

使用JSON.NET来返回ActionResult的问题可以通过重写Json()方法和创建JsonNetResult类来解决。这样可以自定义JSON序列化过程,并实现更灵活、高效的JSON序列化。

0
0 Comments

问题出现的原因是返回的响应头中的content-type为"text/html",而不是"application/json"。解决方法是使用Json.NET库的Content方法来返回ActionResult,并指定content-type为"application/json"。

根据stackoverflow上的答案建议,可以使用以下代码来解决问题:

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

这个解决方法非常简单,能够实现需求。

从hubatish的答案中可以得到启发,我们可以创建一个基于Controller的抽象类,其中包含一个JsonNetResult方法来返回ActionResult。具体代码如下:

public abstract class ControllerBase : Controller

{

protected const string JsonEncoding = "application/json; charset=utf-8";

protected ContentResult JsonNetResult(object result)

{

string json = JsonConvert.SerializeObject(result);

return Content(json, JsonEncoding);

}

}

也许在过去的四年间发生了一些变化,但是根据这个答案中的语法,我的响应头中显示的content-type为"application/json"。

0