Ich möchte einige JSONs domänenübergreifend zurückgeben, und ich verstehe, dass dies eher über JSONP als über reines JSON erfolgt.
Ich verwende ASP.net MVC, also habe ich darüber nachgedacht, nur den JsonResult
Typ und dann den Controller so zu erweitern, dass auch eine Jsonp-Methode implementiert wird.
Ist dies der beste Weg, oder gibt es eine integrierte Funktion ActionResult
, die möglicherweise besser ist?
Lösung : Ich habe das gemacht. Nur als Referenz habe ich ein neues Ergebnis hinzugefügt:
public class JsonpResult : System.Web.Mvc.JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/javascript";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
// The JavaScriptSerializer type was marked as obsolete prior to .NET Framework 3.5 SP1
#pragma warning disable 0618
HttpRequestBase request = context.HttpContext.Request;
JavaScriptSerializer serializer = new JavaScriptSerializer();
response.Write(request.Params["jsoncallback"] + "(" + serializer.Serialize(Data) + ")");
#pragma warning restore 0618
}
}
}
und auch ein paar Methoden zu einer Superklasse aller meiner Controller:
protected internal JsonpResult Jsonp(object data)
{
return Jsonp(data, null /* contentType */);
}
protected internal JsonpResult Jsonp(object data, string contentType)
{
return Jsonp(data, contentType, null);
}
protected internal virtual JsonpResult Jsonp(object data, string contentType, Encoding contentEncoding)
{
return new JsonpResult
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding
};
}
Klappt wunderbar.
json
asp.net-mvc
jsonp
stimms
quelle
quelle
Antworten:
Hier ist eine einfache Lösung, wenn Sie keinen Aktionsfilter definieren möchten
Clientseitiger Code mit jQuery:
$.ajax("http://www.myserver.com/Home/JsonpCall", { dataType: "jsonp" }).done(function (result) {});
MVC-Controller-Aktion. Gibt das Inhaltsergebnis mit JavaScript-Code zurück, der die mit der Abfragezeichenfolge bereitgestellte Rückruffunktion ausführt. Legt auch den JavaScript-MIME-Typ für die Antwort fest.
public ContentResult JsonpCall(string callback) { return Content(String.Format("{0}({1});", callback, new JavaScriptSerializer().Serialize(new { a = 1 })), "application/javascript"); }
quelle
Anstatt meine Controller mit Jsonp () -Methoden zu unterklassifizieren, habe ich mich für die Erweiterungsmethode entschieden, da sie sich für mich etwas sauberer anfühlt. Das Schöne am JsonpResult ist, dass Sie es genauso testen können wie ein JsonResult.
Ich tat:
public static class JsonResultExtensions { public static JsonpResult ToJsonp(this JsonResult json) { return new JsonpResult { ContentEncoding = json.ContentEncoding, ContentType = json.ContentType, Data = json.Data, JsonRequestBehavior = json.JsonRequestBehavior}; } }
Auf diese Weise müssen Sie sich nicht um die Erstellung der verschiedenen Jsonp () - Überladungen kümmern. Konvertieren Sie einfach Ihr JsonResult in ein Jsonp-Ergebnis.
quelle
Ranjus Blog-Post (auch bekannt als "Dieser Blog-Post, den ich gefunden habe") ist ausgezeichnet. Wenn Sie ihn lesen, können Sie die folgende Lösung weiterentwickeln, sodass Ihr Controller JSONP-Anforderungen für dieselbe Domäne und domänenübergreifende JSONP-Anforderungen elegant in derselben Controller-Aktion ohne verarbeiten kann zusätzlicher Code [in der Aktion].
Unabhängig davon, für die Typen "Gib mir den Code", hier ist es, falls der Blog wieder verschwindet.
In Ihrem Controller (dieses Snippet ist neuer / kein Blog-Code):
[AllowCrossSiteJson] public ActionResult JsonpTime(string callback) { string msg = DateTime.UtcNow.ToString("o"); return new JsonpResult { Data = (new { time = msg }) }; }
JsonpResult in diesem ausgezeichneten Blog-Beitrag gefunden :
/// <summary> /// Renders result as JSON and also wraps the JSON in a call /// to the callback function specified in "JsonpResult.Callback". /// http://blogorama.nerdworks.in/entry-EnablingJSONPcallsonASPNETMVC.aspx /// </summary> public class JsonpResult : JsonResult { /// <summary> /// Gets or sets the javascript callback function that is /// to be invoked in the resulting script output. /// </summary> /// <value>The callback function name.</value> public string Callback { get; set; } /// <summary> /// Enables processing of the result of an action method by a /// custom type that inherits from <see cref="T:System.Web.Mvc.ActionResult"/>. /// </summary> /// <param name="context">The context within which the /// result is executed.</param> public override void ExecuteResult(ControllerContext context) { if (context == null) throw new ArgumentNullException("context"); HttpResponseBase response = context.HttpContext.Response; if (!String.IsNullOrEmpty(ContentType)) response.ContentType = ContentType; else response.ContentType = "application/javascript"; if (ContentEncoding != null) response.ContentEncoding = ContentEncoding; if (Callback == null || Callback.Length == 0) Callback = context.HttpContext.Request.QueryString["callback"]; if (Data != null) { // The JavaScriptSerializer type was marked as obsolete // prior to .NET Framework 3.5 SP1 #pragma warning disable 0618 JavaScriptSerializer serializer = new JavaScriptSerializer(); string ser = serializer.Serialize(Data); response.Write(Callback + "(" + ser + ");"); #pragma warning restore 0618 } } }
Hinweis: Nach den Kommentaren von @Ranju und anderen zum OP fand ich, dass es sich lohnt, den Funktionscode "Ran Minimum" aus Ranjus Blog-Post als Community-Wiki zu veröffentlichen. Obwohl man mit Sicherheit sagen kann, dass Ranju den obigen und anderen Code in seinem Blog hinzugefügt hat, um ihn frei zu verwenden, werde ich seine Worte hier nicht kopieren.
quelle
Für ASP.NET Core , NICHT ASP.NET MVC
Dies ist eine maßgeschneiderte Version für ASP.NET CORE der in der Antwort enthaltenen Lösung
public class JsonpResult : JsonResult { public JsonpResult(object value) : base(value) { } public override async Task ExecuteResultAsync(ActionContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); HttpResponse response = context.HttpContext.Response; if (!String.IsNullOrEmpty(ContentType)) response.ContentType = ContentType; else response.ContentType = "application/javascript"; if (Value != null) { HttpRequest request = context.HttpContext.Request; string serializedJson = JsonConvert.SerializeObject(Value); string result = $"{request.Query["callback"]}({serializedJson})"; await response.WriteAsync(result); } } }
quelle
Die Artikel von stimms und ranju v, auf die verwiesen wurde, waren beide sehr nützlich und machten die Situation klar.
Ich kratzte mir jedoch am Kopf, weil ich Erweiterungen verwendet hatte, die im Kontext des MVC-Codes, den ich online gefunden hatte, unterklassifiziert wurden.
Es gab zwei wichtige Punkte, die mich aufgefallen sind:
Wenn Sie also beide kombinieren, brauchte ich keine weiteren Erweiterungen oder Unterklassen, um den Mechanismus für die Rückgabe von JSONP hinzuzufügen. Ändern Sie einfach meine vorhandenen ExecuteResults.
Was mich verwirrt hatte, war, dass ich wirklich nach einer Möglichkeit suchte, JsonResult abzuleiten oder zu erweitern, ohne das ExecuteResult neu zu codieren. Da JSONP effektiv eine JSON-Zeichenfolge mit Präfix und Suffix ist, schien dies eine Verschwendung zu sein. Der Underling ExecuteResult verwendet jedoch respone.write. Die sicherste Möglichkeit zum Ändern besteht darin, ExecuteResults neu zu codieren, wie dies in verschiedenen Postings problemlos möglich ist.
Ich kann Code posten, wenn das nützlich wäre, aber in diesem Thread befindet sich bereits ziemlich viel Code.
quelle
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Script.Serialization; namespace Template.Web.Helpers { public class JsonpResult : JsonResult { public JsonpResult(string callbackName) { CallbackName = callbackName; } public JsonpResult() : this("jsoncallback") { } public string CallbackName { get; set; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } var request = context.HttpContext.Request; var response = context.HttpContext.Response; string jsoncallback = ((context.RouteData.Values[CallbackName] as string) ?? request[CallbackName]) ?? CallbackName; if (!string.IsNullOrEmpty(jsoncallback)) { if (string.IsNullOrEmpty(base.ContentType)) { base.ContentType = "application/x-javascript"; } response.Write(string.Format("{0}(", jsoncallback)); } base.ExecuteResult(context); if (!string.IsNullOrEmpty(jsoncallback)) { response.Write(")"); } } } public static class ControllerExtensions { public static JsonpResult Jsonp(this Controller controller, object data, string callbackName = "callback") { return new JsonpResult(callbackName) { Data = data, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } public static T DeserializeObject<T>(this Controller controller, string key) where T : class { var value = controller.HttpContext.Request.QueryString.Get(key); if (string.IsNullOrEmpty(value)) { return null; } JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer(); return javaScriptSerializer.Deserialize<T>(value); } } } //Example of using the Jsonp function:: // 1- public JsonResult Read() { IEnumerable<User> result = context.All(); return this.Jsonp(result); } //2- public JsonResult Update() { var models = this.DeserializeObject<IEnumerable<User>>("models"); if (models != null) { Update(models); //Update properties & save change in database } return this.Jsonp(models); }
quelle
Die obige Lösung ist eine gute Arbeitsweise, sollte jedoch mit einem neuen Ergebnistyp erweitert werden, anstatt über eine Methode zu verfügen, die ein JsonResult zurückgibt. Sie sollten Methoden schreiben, die Ihre eigenen Ergebnistypen zurückgeben
public JsonPResult testMethod() { // use the other guys code to write a method that returns something } public class JsonPResult : JsonResult { public FileUploadJsonResult(JsonResult data) { this.Data = data; } public override void ExecuteResult(ControllerContext context) { this.ContentType = "text/html"; context.HttpContext.Response.Write("<textarea>"); base.ExecuteResult(context); context.HttpContext.Response.Write("</textarea>"); } }
quelle