Nice programing

JSONP를 반환하는 ASP.net MVC

nicepro 2020. 10. 30. 21:00
반응형

JSONP를 반환하는 ASP.net MVC


도메인간에 일부 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
            };
        }

매력처럼 작동합니다.


액션 필터를 정의하지 않으려는 경우 간단한 해결책이 있습니다.

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

컨트롤러를 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로 변환하기 만하면됩니다.


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 의 블로그 게시물에서 "최소한의"기능 코드를 커뮤니티 위키로 게시 할 가치가 있다고 생각했습니다. Ranju가 자유롭게 사용할 수 있도록 자신의 블로그에 위의 코드와 다른 코드를 추가했다고 말하는 것이 안전하지만 여기에 그의 말을 복사하지는 않겠습니다.


stimms와 ranju v가 언급 한 기사는 매우 유용했고 상황을 명확하게했습니다.

그러나 나는 온라인에서 찾은 MVC 코드의 맥락에서 확장, 하위 클래스를 사용하는 것에 대해 머리를 긁적이었습니다.

저를 사로 잡은 두 가지 핵심 사항이 있습니다.

  1. ActionResult에서 파생 된 코드이지만 ExecuteResult에는 XML 또는 JSON을 반환하는 코드가 있습니다.
  2. 그런 다음 반환 된 데이터 유형과 관계없이 동일한 ExecuteResults가 사용되도록 Generics 기반 ActionResult를 만들었습니다.

따라서 두 가지를 결합하면 JSONP를 반환하는 메커니즘을 추가하기 위해 추가 확장이나 하위 클래스가 필요하지 않았습니다. 기존 ExecuteResults를 변경하기 만하면됩니다.

나를 혼란스럽게 한 것은 실제로 ExecuteResult를 다시 코딩하지 않고 JsonResult를 파생하거나 확장하는 방법을 찾고 있었다는 것입니다. JSONP는 사실상 접두사와 접미사가있는 JSON 문자열이기 때문에 낭비 인 것처럼 보였습니다. 그러나 기본 ExecuteResult는 respone.write를 사용하므로 변경하는 가장 안전한 방법은 다양한 게시에서 제공하는대로 ExecuteResults를 다시 코딩하는 것입니다!

유용 할 경우 일부 코드를 게시 할 수 있지만이 스레드에는 이미 많은 코드가 있습니다.


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

the solution above is a good way of working but it should be extendend with a new type of result instead of having a method that returns a JsonResult you should write methods that return your own result types

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

참고URL : https://stackoverflow.com/questions/758879/asp-net-mvc-returning-jsonp

반응형