72

ドメイン全体で JSON を返すことを検討していますが、これを行う方法は、純粋な JSON ではなく JSONP を使用することであることを理解しています。
私はASP.net MVCを使用しているので、JsonResultタイプを拡張してからコントローラーを拡張して、Jsonpメソッドも実装することを考えていました。これが最善の方法ですか、それともより良い
ビルトインがありますか?ActionResult


解決策:私は先に進みました。参考までに、新しい結果を追加しました。

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

また、すべてのコントローラーのスーパークラスへのいくつかのメソッド:

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

魅力のように機能します。

4

7 に答える 7

17

アクション フィルターを定義したくない場合の簡単な解決策を次に示します。

jQuery を使用したクライアント側コード:

  $.ajax("http://www.myserver.com/Home/JsonpCall", { dataType: "jsonp" }).done(function (result) {});

MVC コントローラー アクション。クエリ文字列で提供されたコールバック関数を実行する JavaScript コードでコンテンツの結果を返します。応答の JavaScript MIME タイプも設定します。

 public ContentResult JsonpCall(string callback)
 {
      return Content(String.Format("{0}({1});",
          callback, 
          new JavaScriptSerializer().Serialize(new { a = 1 })),    
          "application/javascript");
 }
于 2013-03-20T01:13:03.327 に答える
13

コントローラーを Jsonp() メソッドでサブクラス化するのではなく、拡張メソッド ルートを使用しました。JsonpResult の良いところは、JsonResult とまったく同じ方法でテストできることです。

やった:

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

このように、さまざまな Jsonp() オーバーロードをすべて作成することを心配する必要はありません。JsonResult を Jsonp に変換するだけです。

于 2010-12-14T17:50:23.813 に答える
10

Ranju のブログ投稿(別名「このブログ投稿が見つかりました」) は優れており、それを読むと、以下のソリューションをさらに進めて、コントローラーが同じコントローラー アクションで同じドメインの JSON およびクロスドメインの JSONP リクエストをエレガントに処理できるようになります。 [アクション内の] 追加コード。

とにかく、「コードを教えて」タイプの場合は、ブログが再び表示されなくなった場合に備えて、ここにあります。

コントローラーで (このスニペットは新しい/ブログ以外のコードです):

[AllowCrossSiteJson]
public ActionResult JsonpTime(string callback)
{
    string msg = DateTime.UtcNow.ToString("o");
    return new JsonpResult
    {
        Data = (new
        {
            time = msg
        })
    };
}

JsonpResult は、 この優れたブログ投稿で見つかりました:

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

注: @Ranju などによる OP へのコメントをフォローアップした結果、Ranjuのブログ投稿から「最小限の」機能コードをコミュニティ wiki として投稿する価値があると判断しました。Ranju は自由に使用できるように上記のコードやその他のコードをブログに追加したと言っても過言ではありませんが、ここで彼の言葉をコピーするつもりはありません。

于 2013-11-08T14:51:19.107 に答える
0
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);
}
于 2015-08-27T14:15:12.423 に答える
0

stimms と ranju v による参照記事はどちらも非常に役に立ち、状況を明確にしました。

しかし、拡張機能の使用、オンラインで見つけた MVC コードのコンテキストでのサブクラス化について頭を悩ませていました。

私を惹きつけた2つの重要なポイントがありました:

  1. ActionResult から派生したコードですが、ExecuteResult には、XML または JSON を返すコードがいくつかありました。
  2. 次に、Generics ベースの ActionResult を作成し、返されたデータのタイプに関係なく同じ ExecuteResults が使用されるようにしました。

したがって、この 2 つを組み合わせると、JSONP を返すメカニズムを追加するための追加の拡張やサブクラス化は必要なく、単に既存の ExecuteResults を変更するだけです。

私を混乱させたのは、ExecuteResult を再コーディングせずに JsonResult を派生または拡張する方法を実際に探していたことです。JSONP は事実上、接頭辞と接尾辞が付いた JSON 文字列であるため、無駄に思えました。ただし、下層の ExecuteResult は respone.write を使用します。したがって、最も安全な変更方法は、さまざまな投稿で簡単に提供されるように ExecuteResults を再コーディングすることです。

役立つコードがあれば投稿できますが、このスレッドにはすでにかなりの数のコードがあります。

于 2011-07-16T08:33:58.720 に答える
-2

上記の解決策は良い方法ですが、JsonResult を返すメソッドを使用する代わりに、新しいタイプの結果で拡張する必要があります。独自の結果タイプを返すメソッドを作成する必要があります。

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>");
    }
}
于 2011-02-09T19:38:52.577 に答える