JSON.NETを使用してActionResultを返す

私は、モデルをシリアライズして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}

オブジェクトをダブルシリアライズした際に発生する問題だと思います。 他の質問から。 https://stackoverflow.com/questions/22294473/wcf-json-output-is-getting-unwanted-quotes-backslashes-added

まずJSON.NETを使ってシリアライズし、その結果をJson()関数に渡しているので、確かにオブジェクトを二重シリアライズしているように見えます。 参照ループを避けるために手動でシリアライズする必要がありますが、私のViewはActionResultを必要としていると思います。

ここでActionResultを返すにはどうしたらよいでしょうか? それとも文字列を返すだけでいいのでしょうか?

ソリューション

同じようなstackoverflowの質問を見つけました。 https://stackoverflow.com/questions/21938907/json-net-and-actionresult

その回答では

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

私の非常にシンプルなページでは、これでうまくいきそうです。

解説 (4)

JSON.NETでシリアライズして 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シリアライズが行われるようになります。

解説 (7)