MVC: Cómo devolver una cadena como JSON

En un esfuerzo por hacer un proceso de informe de progreso un poco más confiable y desacoplarlo de la solicitud / respuesta, estoy realizando el procesamiento en un Servicio de Windows y persistiendo la respuesta prevista a un archivo. Cuando el cliente comienza a sondear las actualizaciones, la intención es que el controlador devuelva el contenido del archivo, cualquiera que sea su naturaleza, como una cadena JSON.

El contenido del archivo está pre-serializado a JSON. Esto es para garantizar que no haya nada que se interponga en el camino de la respuesta. No es necesario que haya ningún proceso (excepto leer el contenido del archivo en una cadena y devolverlo) para obtener la respuesta.

Inicialmente pensé que esto sería bastante simple, pero no está siendo el caso.

Actualmente, mi método controlador se ve así:

Controlador

Actualizado

[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); } 

Y Fiddler está devolviendo esto como la respuesta cruda

 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

Actualizado

Es probable que lo siguiente sea cambiado más adelante, pero por ahora esto estaba funcionando cuando estaba generando la clase de respuesta y devolviéndola como JSON como una persona normal.

 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; } } 

El problema, creo, es que el resultado de la acción Json está destinado a tomar un objeto (su modelo) y crear una respuesta HTTP con contenido como datos con formato JSON de su objeto modelo.

Sin embargo, lo que está pasando al método Json del controlador es un objeto de cadena con formato JSON, por lo que está “serializando” el objeto de cadena a JSON, razón por la cual el contenido de la respuesta HTTP está rodeado por comillas dobles (I ‘ m suponiendo que ese es el problema).

Creo que puede considerar el uso del resultado de acción de contenido como una alternativa al resultado de la acción Json, ya que esencialmente ya tiene disponible el contenido sin procesar para la respuesta 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 

Otra alternativa sería deserializar el resultado JSON del servicio en un objeto y luego pasar ese objeto al método Json del controlador, pero la desventaja es que se deserializaría y luego volver a serializar los datos, lo que puede ser innecesario. para tus propósitos

Solo necesita devolver ContentResult estándar y configurar ContentType en “application / json”. Puede crear ActionResult personalizado para ello:

 public class JsonStringResult : ContentResult { public JsonStringResult(string json) { Content = json; ContentType = "application/json"; } } 

Y luego devuelve su instancia:

 [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); } 

Sí, eso es todo sin más problemas, para evitar la cadena cruda json, esto es todo.

  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 }; } 

NOTA: tenga en cuenta que el tipo de devolución de método de JsonResult no funciona para mí, ya que JsonResult y ContentResult heredan ActionResult pero no existe relación entre ellos.

Todas las respuestas aquí proporcionan un código bueno y funcional. Pero alguien no estaría satisfecho de que todos usen ContentType como tipo de devolución y no como JsonResult .

Lamentablemente, JsonResult está utilizando JavaScriptSerializer sin opción para deshabilitarlo. La mejor forma de evitar esto es heredar JsonResult .

Copié la mayor parte del código de JsonResult original y JsonStringResult clase JsonStringResult que devuelve una cadena pasada como application/json . El código para esta clase está debajo

 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); } } } 

Ejemplo de uso:

 var json = JsonConvert.SerializeObject(data); return new JsonStringResult(json);