Um einen Fortschrittsberichtsprozess ein wenig zuverlässiger zu gestalten und ihn von der Anforderung / Antwort zu entkoppeln, führe ich die Verarbeitung in einem Windows-Dienst durch und behalte die beabsichtigte Antwort auf eine Datei bei. Wenn der Client nach Updates fragt, beabsichtigt der Controller, den Inhalt der Datei, unabhängig davon, was sie sind, als JSON-Zeichenfolge zurückzugeben.
Der Inhalt der Datei wird in JSON vorserialisiert. Dies soll sicherstellen, dass der Antwort nichts im Wege steht. Es muss keine Verarbeitung stattfinden (es sei denn, der Dateiinhalt wird in eine Zeichenfolge eingelesen und zurückgegeben), um die Antwort zu erhalten.
Ich dachte zunächst, dies wäre ziemlich einfach, aber es stellt sich nicht heraus, dass dies der Fall ist.
Derzeit sieht meine Controller-Methode folgendermaßen aus:
Regler
Aktualisiert
[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);
}
Und Fiddler gibt dies als rohe Antwort zurück
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
Aktualisiert
Das Folgende wird wahrscheinlich später geändert, aber im Moment funktionierte dies, als ich die Antwortklasse generierte und sie wie eine normale Person als JSON zurückgab.
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;
}
}
quelle
path
Variable irgendwo in Ihrer Controller-Aktion verwenden. Wo lesen Sie den Inhalt der Datei? Sie geben lediglich einen JSON mit dem Inhalt derProperties.Settings.Default.EmptyBatchSearchUpdate
Eigenschaft zurück. Wussten Sie auch, dass Sie eine Datei nicht lesen können, während ein anderer Thread darauf schreibt? Zumindest kann dies nicht auf sichere Weise geschehen. Sie könnten sehr schnell auf Rennbedingungen stoßen. Ich denke also, dass Ihr Design von Anfang an fehlerhaft ist.Antworten:
Ich glaube, das Problem ist, dass das Ergebnis der Json-Aktion ein Objekt (Ihr Modell) nehmen und eine HTTP-Antwort mit Inhalt als JSON-formatierten Daten aus Ihrem Modellobjekt erstellen soll.
Was Sie jedoch an die Json-Methode des Controllers übergeben, ist ein JSON-formatiertes Zeichenfolgenobjekt. Daher wird das Zeichenfolgenobjekt in JSON "serialisiert", weshalb der Inhalt der HTTP-Antwort in doppelte Anführungszeichen gesetzt ist (I '). Ich gehe davon aus, dass dies das Problem ist.
Ich denke, Sie können das Ergebnis der Inhaltsaktion als Alternative zum Ergebnis der Json-Aktion verwenden, da Sie im Wesentlichen bereits über den Rohinhalt für die HTTP-Antwort verfügen.
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
Eine andere Alternative wäre, das JSON-Ergebnis aus dem Dienst in ein Objekt zu deserialisieren und dieses Objekt dann an die Json-Methode des Controllers zu übergeben. Der Nachteil besteht jedoch darin, dass Sie die Daten de-serialisieren und dann erneut serialisieren, was möglicherweise unnötig ist für Ihre Zwecke.
quelle
Content
zurückkehrt,ContentResult
wohinJson
zurückkehrtJsonResult
.Sie müssen nur das Standard-ContentResult zurückgeben und ContentType auf "application / json" setzen. Sie können ein benutzerdefiniertes ActionResult dafür erstellen:
public class JsonStringResult : ContentResult { public JsonStringResult(string json) { Content = json; ContentType = "application/json"; } }
Und dann geben Sie die Instanz zurück:
[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); }
quelle
Ja, das ist es ohne weitere Probleme, um rohen String json zu vermeiden, das ist es.
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 }; }
Hinweis: Bitte beachten Sie , dass die Methode Rückgabetyp
JsonResult
ist für mich nicht funktioniert, daJsonResult
undContentResult
beide erben ,ActionResult
aber es gibt keine Beziehung zwischen ihnen.quelle
Verwenden Sie den folgenden Code in Ihrem Controller:
return Json(new { success = string }, JsonRequestBehavior.AllowGet);
und in JavaScript:
success: function (data) { var response = data.success; .... }
quelle
Alle Antworten hier liefern guten und funktionierenden Code. Aber jemand wäre unzufrieden, dass sie alle
ContentType
als Rückgabetyp verwenden und nichtJsonResult
.Leider
JsonResult
wirdJavaScriptSerializer
ohne Option zum Deaktivieren verwendet. Der beste Weg, dies zu umgehen, ist zu erbenJsonResult
.Ich habe den größten Teil des Codes aus dem Original kopiert
JsonResult
und eineJsonStringResult
Klasse erstellt, die die übergebene Zeichenfolge als zurückgibtapplication/json
. Der Code für diese Klasse ist untenpublic 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); } } }
Anwendungsbeispiel:
var json = JsonConvert.SerializeObject(data); return new JsonStringResult(json);
quelle