Dans le but de rendre le processus de rapport d'avancement un peu plus fiable et de le dissocier de la demande/réponse, je suis en train d'effectuer le traitement dans un service Windows et de conserver la réponse souhaitée à un fichier. Lorsque le client commence à interroger les mises à jour, le contrôleur renvoie le contenu du fichier, quel qu'il soit, sous forme de chaîne JSON.
Le contenu du fichier est pré-sérialisé en JSON. Cela permet de s’assurer que rien ne fait obstacle à la réponse. Aucun traitement n'est nécessaire (à moins de lire le contenu du fichier dans une chaîne et de le renvoyer) pour obtenir la réponse.
Au départ, je pensais que cela serait assez simple, mais ce n’est pas le cas.
Actuellement, ma méthode de contrôleur ressemble à ceci:
[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);
}
Et Fiddler renvoie ceci comme réponse brute
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\":[]}"
Les éléments suivants seront probablement modifiés ultérieurement, mais pour l'instant, cela fonctionnait lorsque je générais la classe de réponse et que je le retournais sous forme de code JSON, comme une personne 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;
}
}
Le problème, à mon avis, est que le résultat de l'action Json est destiné à prendre un objet (votre modèle) et à créer une réponse HTTP avec un contenu sous la forme de données au format JSON à partir de votre objet modèle.
Ce que vous transmettez à la méthode Json du contrôleur, cependant, est un objet string au format JSON. Il s'agit donc de "sérialiser" l'objet string en JSON. citations (je suppose que c'est le problème).
Je pense que vous pouvez envisager d'utiliser le résultat de l'action Content comme alternative au résultat de l'action Json, car vous disposez déjà du contenu brut pour la réponse 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
Une autre solution consisterait à désérialiser le résultat JSON du service en un objet, puis à le transmettre à la méthode Json du contrôleur, mais le désavantage serait que vous désérialiseriez puis resérialiseriez les données, ce qui peut être inutile. pour vos buts.
Vous devez simplement renvoyer ContentResult standard et définir ContentType sur "application/json" . Vous pouvez créer un ActionResult personnalisé pour celui-ci:
public class JsonStringResult : ContentResult
{
public JsonStringResult(string json)
{
Content = json;
ContentType = "application/json";
}
}
Et puis retourne son exemple:
[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);
}
Ouais c'est tout, sans autre problème, pour éviter la chaîne brute json c'est ça.
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
};
}
REMARQUE: notez que le type de retour de méthode JsonResult
ne fonctionne pas pour moi, car JsonResult
et ContentResult
héritent tous deux de ActionResult
mais il n'y a pas de relation entre eux.
Toutes les réponses ici fournissent un bon code et qui fonctionne. Mais quelqu'un serait mécontent du fait qu'ils utilisent tous ContentType
comme type de retour et non JsonResult
.
Malheureusement, JsonResult
utilise JavaScriptSerializer
sans option pour le désactiver. Le meilleur moyen de contourner ce problème est d’hériter de JsonResult
.
J'ai copié la plupart du code de l'original JsonResult
et créé la classe JsonStringResult
qui renvoie la chaîne passée sous la forme application/json
. Le code pour cette classe est ci-dessous
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);
}
}
}
Exemple d'utilisation:
var json = JsonConvert.SerializeObject(data);
return new JsonStringResult(json);
Utilisez le code suivant sur votre contrôleur:
return Json(new { success = string }, JsonRequestBehavior.AllowGet);
et en JavaScript:
success: function (data) {
var response = data.success;
....
}