ASP.NET Web API 自定義MediaType實現jsonp跨域呼叫

丶Pz發表於2016-07-14

  程式碼來自《ASP.NET Web API 2 框架揭祕》一書。

  直接上程式碼:

  

 /// <summary>
    /// 自定義jsonp MediaType
    /// </summary>
    public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
    {
        //callback引數
        public string Callback { get; private set; }
        public JsonpMediaTypeFormatter(string callback = null)
        {
            this.Callback = callback;
        }

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            //如果callback不存在,直接呼叫父類方法
            if (string.IsNullOrEmpty(this.Callback))
            {
                return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
            }
            try
            {
                //否則呼叫重寫的方法
                this.WriteToStream(type, value, writeStream, content);
                return Task.FromResult<AsyncVoid>(new AsyncVoid());
            }
            catch(Exception ex)
            {
                TaskCompletionSource<AsyncVoid> source = new TaskCompletionSource<AsyncVoid>();
                source.SetException(ex);
                return source.Task;
            }
        }


        private void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
        {
            JsonSerializer serializer = JsonSerializer.Create(this.SerializerSettings);
            using (StreamWriter writer = new StreamWriter(writeStream,this.SupportedEncodings.First())) {
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter(writer) { CloseOutput = false }) {
                    //新增callback(json)
                    jsonTextWriter.WriteRaw(this.Callback + "(");
                    serializer.Serialize(jsonTextWriter, value);
                    jsonTextWriter.WriteRaw(")");
                }
            }
        }

        public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
        {

            if (request.Method != HttpMethod.Get) { return this; }
            string callback;
            if (request.GetQueryNameValuePairs().ToDictionary(p => p.Key, p => p.Value).TryGetValue("callback", out callback)) {
                return new JsonpMediaTypeFormatter(callback);
            }
            return this;
        }

        [StructLayout(LayoutKind.Sequential, Size = 1)]
        private struct AsyncVoid { }
    }

  然後在Global.asax中將JsonpMediaTypeFormatter加入

  

 protected void Application_Start()
        { 
            //加入jsonpMediaTypeFormatter
            GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter());
            AreaRegistration.RegisterAllAreas();
         
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

  Demo演示:

  我在localhost:55950 用jquery 呼叫api(http://localhost:55599/api/search?key=%E7%83%A7%E7%81%AB&from=0&size=10)

  

  得到結果如圖:

  

  成功呼叫。不過書上說,這種方法僅限於get方法。

  OK,筆記完成,記錄下來以防以後 用到可以參考參考。

相關文章