MVC: come restituire una stringa come JSON

Nel tentativo di rendere un processo di reporting di avanzamento un po ‘più affidabile e disaccoppiare dalla richiesta / risposta, sto eseguendo l’elaborazione in un servizio di Windows e persistendo la risposta prevista a un file. Quando il client avvia il polling per gli aggiornamenti, l’intenzione è che il controller restituisca il contenuto del file, qualunque esso sia, come una stringa JSON.

I contenuti del file sono pre-serializzati su JSON. Questo per garantire che non ci sia nulla che ostacoli la risposta. Non è necessario eseguire alcuna elaborazione (non è sufficiente leggere il contenuto del file in una stringa e restituirlo) per ottenere la risposta.

Inizialmente, questo sarebbe abbastanza semplice, ma non è il caso.

Attualmente il mio metodo di controllo sembra così:

controllore

aggiornato

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

E Fiddler sta restituendo questo come la risposta grezza

 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

aggiornato

Quanto segue verrà probabilmente modificato in seguito, ma per ora ciò funzionava mentre stavo generando la class di risposta e restituendola come JSON come una persona normale.

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

Il problema, credo, è che il risultato dell’azione Json è destinato a prendere un object (il modello) e creare una risposta HTTP con contenuto come i dati in formato JSON dall’object del modello.

Quello che state passando al metodo JSON del controller, però, è un object stringa formattato JSON, quindi è “serializzare” l’object stringa su JSON, motivo per cui il contenuto della risposta HTTP è circondato da virgolette (I ‘ supponendo che questo sia il problema).

Penso che si possa considerare l’utilizzo del risultato dell’azione Contenuto come alternativa al risultato dell’azione Json, poiché in pratica è già disponibile il contenuto non elaborato per la risposta 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 

Un’altra alternativa sarebbe quella di deserializzare il risultato JSON dal servizio in un object e quindi passare quell’object al metodo Json del controller, ma lo svantaggio è che si declassificherà e quindi si serializzerà nuovamente i dati, il che potrebbe non essere necessario per i tuoi scopi.

Devi solo restituire ContentResult standard e impostare ContentType su “application / json”. Puoi creare ActionResult personalizzato per questo:

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

E quindi restituire è istanza:

 [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ì, questo è tutto, senza ulteriori problemi, per evitare la stringa raw JSON questo è tutto.

  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: si noti che il metodo return type di JsonResult non funziona per me, poiché JsonResult e ContentResult ereditano ActionResult ma non esiste alcuna relazione tra di essi.

Tutte le risposte qui forniscono un codice buono e funzionante. Ma qualcuno sarebbe insoddisfatto che tutti usino ContentType come tipo di ritorno e non come JsonResult .

Sfortunatamente JsonResult sta usando JavaScriptSerializer senza opzione per disabilitarlo. Il modo migliore per aggirare questo è ereditare JsonResult .

Ho copiato la maggior parte del codice da JsonResult originale e JsonStringResult creato la class JsonStringResult che restituisce la stringa passata come application/json . Il codice per questa class è sotto

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

Esempio di utilizzo:

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