복붙노트

[JQUERY] ASP.NET 웹 API와 JSONP

JQUERY

ASP.NET 웹 API와 JSONP

해결법


  1. 1.이 질문을 한 후, 나는 마침내 내가 대답하고 그래서 내가 필요한 것을 발견했다.

    이 질문을 한 후, 나는 마침내 내가 대답하고 그래서 내가 필요한 것을 발견했다.

    나는이 JsonpMediaTypeFormatter을 가로 질러 달렸다. 이렇게하여 Global.asax에의 위해 Application_Start로 추가 :

    var config = GlobalConfiguration.Configuration;
    config.Formatters.Insert(0, new JsonpMediaTypeFormatter());
    

    당신은 JQuery와 AJAX 호출로 갈 좋은 것을 다음과 같다 :

    $.ajax({
        url: 'http://myurl.com',
        type: 'GET',
        dataType: 'jsonp',
        success: function (data) {
            alert(data.MyProperty);
        }
    })
    

    그것은 매우 잘 작동하는 것 같다.


  2. 2.여기에 웹 API RC와 함께 사용하기위한 JsonMediaTypeFormatter의 업데이트 버전입니다 :

    여기에 웹 API RC와 함께 사용하기위한 JsonMediaTypeFormatter의 업데이트 버전입니다 :

    public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
    {
        private string callbackQueryParameter;
    
        public JsonpMediaTypeFormatter()
        {
            SupportedMediaTypes.Add(DefaultMediaType);
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
    
            MediaTypeMappings.Add(new UriPathExtensionMapping("jsonp", DefaultMediaType));
        }
    
        public string CallbackQueryParameter
        {
            get { return callbackQueryParameter ?? "callback"; }
            set { callbackQueryParameter = value; }
        }
    
        public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
        {
            string callback;
    
            if (IsJsonpRequest(out callback))
            {
                return Task.Factory.StartNew(() =>
                {
                    var writer = new StreamWriter(stream);
                    writer.Write(callback + "(");
                    writer.Flush();
    
                    base.WriteToStreamAsync(type, value, stream, content, transportContext).Wait();
    
                    writer.Write(")");
                    writer.Flush();
                });
            }
            else
            {
                return base.WriteToStreamAsync(type, value, stream, content, transportContext);
            }
        }
    
    
        private bool IsJsonpRequest(out string callback)
        {
            callback = null;
    
            if (HttpContext.Current.Request.HttpMethod != "GET")
                return false;
    
            callback = HttpContext.Current.Request.QueryString[CallbackQueryParameter];
    
            return !string.IsNullOrEmpty(callback);
        }
    }
    

  3. 3.이 같은 ActionFilterAttribute을 사용할 수 있습니다 :

    이 같은 ActionFilterAttribute을 사용할 수 있습니다 :

    public class JsonCallbackAttribute : ActionFilterAttribute
    {
        private const string CallbackQueryParameter = "callback";
    
        public override void OnActionExecuted(HttpActionExecutedContext context)
        {
            var callback = string.Empty;
    
            if (IsJsonp(out callback))
            {
                var jsonBuilder = new StringBuilder(callback);
    
                jsonBuilder.AppendFormat("({0})", context.Response.Content.ReadAsStringAsync().Result);
    
                context.Response.Content = new StringContent(jsonBuilder.ToString());
            }
    
            base.OnActionExecuted(context);
        }
    
        private bool IsJsonp(out string callback)
        {
            callback = HttpContext.Current.Request.QueryString[CallbackQueryParameter];
    
            return !string.IsNullOrEmpty(callback);
        }
    }
    

    그런 다음 행동에 넣어 :

    [JsonCallback]
    public IEnumerable<User> User()
    {
        return _user;
    }
    

  4. 4.물론 브라이언의 대답은 이미 당신에게 꽤 JSON 날짜와 빠른 직렬화를 제공하는의 Json.Net 포맷터를 사용하지만 경우, 올바른 하나입니다, 당신은 단지 JSONP에 대한 두 번째 포매터를 추가 할 수 없습니다, 당신은 두 가지를 결합해야합니다. 스콧 Hanselman은이 ASP.NET 웹 API의 출시는 기본적으로 Json.Net 시리얼 라이저를 사용하려고했다 것처럼 어쨌든 그것을 사용하는 좋은 아이디어이다.

    물론 브라이언의 대답은 이미 당신에게 꽤 JSON 날짜와 빠른 직렬화를 제공하는의 Json.Net 포맷터를 사용하지만 경우, 올바른 하나입니다, 당신은 단지 JSONP에 대한 두 번째 포매터를 추가 할 수 없습니다, 당신은 두 가지를 결합해야합니다. 스콧 Hanselman은이 ASP.NET 웹 API의 출시는 기본적으로 Json.Net 시리얼 라이저를 사용하려고했다 것처럼 어쨌든 그것을 사용하는 좋은 아이디어이다.

    public class JsonNetFormatter : MediaTypeFormatter
        {
            private JsonSerializerSettings _jsonSerializerSettings;
            private string callbackQueryParameter;
    
            public JsonNetFormatter(JsonSerializerSettings jsonSerializerSettings)
            {
                _jsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings();
    
                // Fill out the mediatype and encoding we support
                SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
                Encoding = new UTF8Encoding(false, true);
    
                //we also support jsonp.
                SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
                MediaTypeMappings.Add(new UriPathExtensionMapping("jsonp", "application/json"));
            }
    
            public string CallbackQueryParameter
            {
                get { return callbackQueryParameter ?? "jsoncallback"; }
                set { callbackQueryParameter = value; }
            }
    
            protected override bool CanReadType(Type type)
            {
                if (type == typeof(IKeyValueModel))
                    return false;
    
                return true;
            }
    
            protected override bool CanWriteType(Type type)
            {
                return true;
            }
    
            protected override Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders,
                FormatterContext formatterContext)
            {
                // Create a serializer
                JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);
    
                // Create task reading the content
                return Task.Factory.StartNew(() =>
                {
                    using (StreamReader streamReader = new StreamReader(stream, Encoding))
                    {
                        using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader))
                        {
                            return serializer.Deserialize(jsonTextReader, type);
                        }
                    }
                });
            }
    
            protected override Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders,
                FormatterContext formatterContext, TransportContext transportContext)
            {
                string callback;
                var isJsonp = IsJsonpRequest(formatterContext.Response.RequestMessage, out callback);
    
                // Create a serializer
                JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);
    
                // Create task writing the serialized content
                return Task.Factory.StartNew(() =>
                {
                    using (JsonTextWriter jsonTextWriter = new JsonTextWriter(new StreamWriter(stream, Encoding)) { CloseOutput = false })
                    {
                        if (isJsonp)
                        {
                            jsonTextWriter.WriteRaw(callback + "(");
                            jsonTextWriter.Flush();
                        }
    
                        serializer.Serialize(jsonTextWriter, value);
                        jsonTextWriter.Flush();
    
                        if (isJsonp)
                        {
                            jsonTextWriter.WriteRaw(")");
                            jsonTextWriter.Flush();
                        }
                    }
                });
            }
    
            private bool IsJsonpRequest(HttpRequestMessage request, out string callback)
            {
                callback = null;
    
                if (request.Method != HttpMethod.Get)
                    return false;
    
                var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
                callback = query[CallbackQueryParameter];
    
                return !string.IsNullOrEmpty(callback);
            }
        }
    

  5. 5.릭 Strahl의 구현은 RC와 나를 위해 최선을 다했다.

    릭 Strahl의 구현은 RC와 나를 위해 최선을 다했다.


  6. 6.JSONP는 HTTP GET 요청을 작동합니다. 모든 HTTP 동사와 함께 잘 작동 asp.net 웹 API에 CORS 지원이있다.

    JSONP는 HTTP GET 요청을 작동합니다. 모든 HTTP 동사와 함께 잘 작동 asp.net 웹 API에 CORS 지원이있다.

    이 문서가 당신에게 도움이 될 수있다.


  7. 7.업데이트

    업데이트

    public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
        {
            private string callbackQueryParameter;
    
            public JsonpMediaTypeFormatter()
            {
                SupportedMediaTypes.Add(DefaultMediaType);
                SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
    
                MediaTypeMappings.Add(new UriPathExtensionMapping("jsonp", DefaultMediaType));
            }
    
            public string CallbackQueryParameter
            {
                get { return callbackQueryParameter ?? "callback"; }
                set { callbackQueryParameter = value; }
            }
    
            public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
            {
                string callback;
    
                if (IsJsonpRequest(out callback))
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var writer = new StreamWriter(writeStream);
                        writer.Write(callback + "(");
                        writer.Flush();
    
                        base.WriteToStreamAsync(type, value, writeStream, content, transportContext).Wait();
    
                        writer.Write(")");
                        writer.Flush();
                    });
                }
                else
                {
                    return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
                }
            }
    
            private bool IsJsonpRequest(out string callback)
            {
                callback = null;
    
                if (HttpContext.Current.Request.HttpMethod != "GET")
                    return false;
    
                callback = HttpContext.Current.Request.QueryString[CallbackQueryParameter];
    
                return !string.IsNullOrEmpty(callback);
            }
        }
    

  8. 8.여기에 웹 API를 RTM 버전에서 작동 여러 개선과 업데이트 버전입니다.

    여기에 웹 API를 RTM 버전에서 작동 여러 개선과 업데이트 버전입니다.

    암호:

    public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
    {
      private string _callbackQueryParameter;
    
      public JsonpMediaTypeFormatter()
      {
        SupportedMediaTypes.Add(DefaultMediaType);
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/javascript"));
    
        // need a lambda here so that it'll always get the 'live' value of CallbackQueryParameter.
        MediaTypeMappings.Add(new Mapping(() => CallbackQueryParameter, "application/javascript"));
      }
    
      public string CallbackQueryParameter
      {
        get { return _callbackQueryParameter ?? "callback"; }
        set { _callbackQueryParameter = value; }
      }
    
      public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
                                              TransportContext transportContext)
      {
        var callback = GetCallbackName();
    
        if (!String.IsNullOrEmpty(callback))
        {
          // select the correct encoding to use.
          Encoding encoding = SelectCharacterEncoding(content.Headers);
    
          // write the callback and opening paren.
          return Task.Factory.StartNew(() =>
            {
              var bytes = encoding.GetBytes(callback + "(");
              writeStream.Write(bytes, 0, bytes.Length);
            })
          // then we do the actual JSON serialization...
          .ContinueWith(t => base.WriteToStreamAsync(type, value, writeStream, content, transportContext))
    
          // finally, we close the parens.
          .ContinueWith(t =>
            {
              var bytes = encoding.GetBytes(")");
              writeStream.Write(bytes, 0, bytes.Length);
            });
        }
        return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
      }
    
      private string GetCallbackName()
      {
        if (HttpContext.Current.Request.HttpMethod != "GET")
          return null;
        return HttpContext.Current.Request.QueryString[CallbackQueryParameter];
      }
    
      #region Nested type: Mapping
    
      private class Mapping : MediaTypeMapping
      {
        private readonly Func<string> _param; 
    
        public Mapping(Func<string> discriminator, string mediaType)
          : base(mediaType)
        {
          _param = discriminator;
        }
    
        public override double TryMatchMediaType(HttpRequestMessage request)
        {
          if (request.RequestUri.Query.Contains(_param() + "="))
            return 1.0;
          return 0.0;
        }
      }
    
      #endregion
    }
    

    나는 Func을 <문자열>의 "hackiness"알고 있어요 내부 클래스 생성자에 매개 변수지만, 그것이 해결 문제를 해결하기 위해 가장 빠른 방법이었다 - C 번호는 정적 내부 클래스를 가지고 있기 때문에, 그것을 볼 수 있습니다 CallbackQueryParameter 속성입니다. 매핑 TryMatchMediaType 년에 나중에 액세스 할 수 있도록, 람다에 바인딩에서 속성을 Func을 전달. 좀 더 우아한 방법이 있다면, 코멘트를하시기 바랍니다!


  9. 9.내가 대답을 게시합니다 불행하게도, 나는 의견을 충분히 평판이 없습니다. @Justin 표준 JsonFormatter 나란히 WebApiContrib.Formatting.Jsonp 포매터를 실행의 문제를 제기했다. 그 문제는 최신 릴리스에서 해결되었습니다 (실제로 얼마 전에 발표). 또한, 최신 웹 API 릴리스와 함께 작동합니다.

    내가 대답을 게시합니다 불행하게도, 나는 의견을 충분히 평판이 없습니다. @Justin 표준 JsonFormatter 나란히 WebApiContrib.Formatting.Jsonp 포매터를 실행의 문제를 제기했다. 그 문제는 최신 릴리스에서 해결되었습니다 (실제로 얼마 전에 발표). 또한, 최신 웹 API 릴리스와 함께 작동합니다.


  10. 10.johperl, 토마스. 위의 피터 모 베르그에 의해 주어진 답은 NewtonSoft JSON 시리얼 이미 그 용도에서 상속하는 JsonMediaTypeFormatter로 RC 버전에 대한 정확해야하고, 그래서 그는 어떤 변화 밖으로 작동합니다 것을.

    johperl, 토마스. 위의 피터 모 베르그에 의해 주어진 답은 NewtonSoft JSON 시리얼 이미 그 용도에서 상속하는 JsonMediaTypeFormatter로 RC 버전에 대한 정확해야하고, 그래서 그는 어떤 변화 밖으로 작동합니다 것을.

    땅에 여전히 매개 변수 명을 사용하는 이유 그러나, 당신은 다음을 때 할 수있는

    public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext transportContext)
            {
                var isJsonpRequest = IsJsonpRequest();
    
                if(isJsonpRequest.Item1)
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var writer = new StreamWriter(stream);
                        writer.Write(isJsonpRequest.Item2 + "(");
                        writer.Flush();
                        base.WriteToStreamAsync(type, value, stream, contentHeaders, transportContext).Wait();
                        writer.Write(")");
                        writer.Flush();
                    });
                }
    
                return base.WriteToStreamAsync(type, value, stream, contentHeaders, transportContext);
            }
    
            private Tuple<bool, string> IsJsonpRequest()
            {
                if(HttpContext.Current.Request.HttpMethod != "GET")
                    return new Tuple<bool, string>(false, null);
    
                var callback = HttpContext.Current.Request.QueryString[CallbackQueryParameter];
    
                return new Tuple<bool, string>(!string.IsNullOrEmpty(callback), callback);
            }
    

  11. 11.대신 버전 포맷터 자신의 JSONP를 호스팅 당신은 이미 구현 하나 WebApiContrib.Formatting.Jsonp NuGet 패키지를 설치할 수 있습니다 (버전을 선택 당신의 .NET 프레임 워크에 대한 작품).

    대신 버전 포맷터 자신의 JSONP를 호스팅 당신은 이미 구현 하나 WebApiContrib.Formatting.Jsonp NuGet 패키지를 설치할 수 있습니다 (버전을 선택 당신의 .NET 프레임 워크에 대한 작품).

    위해 Application_Start에이 포매터를 추가 :

    GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter(new JsonMediaTypeFormatter()));
    

  12. 12.그것은 자기 호스트 서버에 존재하지 않기 때문에 HttpSelfHostServer이 부분의 코드는, HttpContext.Current 실패합니다 사용하는 분들을 위해.

    그것은 자기 호스트 서버에 존재하지 않기 때문에 HttpSelfHostServer이 부분의 코드는, HttpContext.Current 실패합니다 사용하는 분들을 위해.

    private Tuple<bool, string> IsJsonpRequest()
    {
    if(HttpContext.Current.Request.HttpMethod != "GET")
     return new Tuple<bool, string>(false, null);
     var callback = HttpContext.Current.Request.QueryString[CallbackQueryParameter];
     return new Tuple<bool, string>(!string.IsNullOrEmpty(callback), callback);
     }
    

    그러나이 재정을 통해 자체 호스트 "컨텍스트"를 가로 챌 수 있습니다.

    public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
            {
                _method = request.Method;
                _callbackMethodName =
                    request.GetQueryNameValuePairs()
                           .Where(x => x.Key == CallbackQueryParameter)
                           .Select(x => x.Value)
                           .FirstOrDefault();
    
                return base.GetPerRequestFormatterInstance(type, request, mediaType);
            }
    

    request.Method, 당신은 "GET"등 "POST"를 줄 것이다 및 GetQueryNameValuePairs은? 콜백 매개 변수를 검색 할 수 있습니다. 따라서 내 수정 된 코드 모습 좋아 :

    private Tuple<bool, string> IsJsonpRequest()
     {
         if (_method.Method != "GET")
         return new Tuple<bool, string>(false, null);
    
         return new Tuple<bool, string>(!string.IsNullOrEmpty(_callbackMethodName), _callbackMethodName);
    }
    

    이것은 당신의 일부를 도움이되기를 바랍니다. 당신이 필요하지 않습니다이 방법은 HttpContext를 심합니다.

    씨.


  13. 13.이 하나의 체크 아웃. 도움이된다면 참조하십시오.

    이 하나의 체크 아웃. 도움이된다면 참조하십시오.

    웹 API와 JSONP


  14. 14.문맥 웹 API를 하라구요 010227leo의 대답을 참조하는 경우, 당신은 null이 될 것입니다 WebContext.Current 값을 고려해야합니다.

    문맥 웹 API를 하라구요 010227leo의 대답을 참조하는 경우, 당신은 null이 될 것입니다 WebContext.Current 값을 고려해야합니다.

    나는이 자신의 코드를 업데이트 그래서 :

    public class JsonCallbackAttribute
        : ActionFilterAttribute
    {
        private const string CallbackQueryParameter = "callback";
    
        public override void OnActionExecuted(HttpActionExecutedContext context)
        {
            var callback = context.Request.GetQueryNameValuePairs().Where(item => item.Key == CallbackQueryParameter).Select(item => item.Value).SingleOrDefault();
    
            if (!string.IsNullOrEmpty(callback))
            {
                var jsonBuilder = new StringBuilder(callback);
    
                jsonBuilder.AppendFormat("({0})", context.Response.Content.ReadAsStringAsync().Result);
    
                context.Response.Content = new StringContent(jsonBuilder.ToString());
            }
    
            base.OnActionExecuted(context);
        }
    }
    

  15. 15.우리는 두 가지 방법을 사용하여 CORS (교차 원산지 자원 공유) 문제를 해결할 수 있습니다

    우리는 두 가지 방법을 사용하여 CORS (교차 원산지 자원 공유) 문제를 해결할 수 있습니다

    1) JSONP 사용 2) 고르 활성화

    1) Jsonp- 사용 우리가 WebApiContrib.Formatting.Jsonp의 nuget 패키지를 설치하는 데 필요한 JSONP를 사용하는 와, 스크린 샷을 참조 WebApiConfig.cs에 JsonpFormmater를 추가 할 필요가

    jQuery 코드

    2) CORS를 사용 -

    우리가 Microsoft.AspNet.WebApi.Cors에게 nuget 패키지와 WebApiConfig.cs이 스크린 샷을 참조로 고르를 활성화해야합니다을 추가해야 CORS를 사용하려면

    더 참고로, 다음과 같은 링크를 사용하여 GitHub의에서 내 샘플의 repo를 참조 할 수 있습니다. https://github.com/mahesh353/Ninject.WebAPi/tree/develop

  16. from https://stackoverflow.com/questions/9421312/jsonp-with-asp-net-web-api by cc-by-sa and MIT license