zoukankan      html  css  js  c++  java
  • 通过扩展让ASP.NET Web API支持JSONP

    我们通过继承JsonMediaTypeFormatter定义了如下一个JsonpMediaTypeFormatter类型。它的只读属性Callback代表JavaScript回调函数名称,改属性在构造函数中指定。在重写的方法WriteToStreamAsync中,对于非JSONP调用(回调函数不存在),我们直接调用基类的同名方法对响应对象实施针对JSON的序列化,否则调用WriteToStream方法将对象序列化后的JSON字符串填充到JavaScript回调函数中。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Formatting;
    using System.Net.Http.Headers;
    using System.Runtime.InteropServices;
    using System.Threading.Tasks;
    using System.Web;
    using Newtonsoft.Json;
    
    namespace MvcApplication2.Attributes
    {
        public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
        {
            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)
            {
                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 exception)
                {
                    TaskCompletionSource<AsyncVoid> source = new TaskCompletionSource<AsyncVoid>();
                    source.SetException(exception);
                    return source.Task;
                }
            }
    
            private void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
            {
                JsonSerializer serializer = JsonSerializer.Create(this.SerializerSettings);
                using (StreamWriter streamWriter = new StreamWriter(writeStream, this.SupportedEncodings.First()))
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter) {CloseOutput = false})
                {
                    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(pair => pair.Key,
                    pair => pair.Value).TryGetValue("callback", out callback))
                {
                    return new JsonpMediaTypeFormatter(callback);
                }
                return this;
            }
    
            [StructLayout(LayoutKind.Sequential, Size = 1)]
            private struct AsyncVoid
            {
    
            }
        }
    }

    我们重写了GetPerRequestFormatterInstance方法,在默认情况下,当ASP.NET Web API采用内容协商机制选择出与当前请求相匹配的MediaTypeFormatter后,会调用此方法来创建真正用于序列化响应结果的MediaTypeFormatter对象。在重写的这个GetPerRequestFormatterInstance方法中,我们尝试从请求的URL中得到携带的JavaScript回调函数名称,即一个名为“callback”的查询字符串。如果回调函数名不存在,则直接返回自身,否则返回据此创建的JsonpMediaTypeFormatter对象。

    将JsonpMediaTypeFormatter的应用到ASP.NET Web API中    

    现在我们在WebApi应用的Global.asax中利用如下的程序创建这个JsonpMediaTypeFormatter对象并添加当前注册的MediaTypeFormatter列表中。为了让它被优先选择,我们将这个JsonpMediaTypeFormatter对象放在此列表的最前端。

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

    在ASP.NET MVC中调用:

    <script src="~/Scripts/jquery-1.7.1.js"></script>
    <script type="text/javascript">
        $(function() {
    
            $("#btnTest").click(function() {
                $.ajax({
                    Type       : "GET",   
                    url: "http://localhost:6120/api/values/5",
                    dataType   : "jsonp",   
                    success: function(data) {
                        alert(data);
                    }
    
                });
    
            });
        });
    </script>
    <input type="button" value="click" id="btnTest" />
  • 相关阅读:
    Apache ActiveMQ 远程代码执行漏洞 (CVE-2016-3088)案例分析
    linux 软中断过高性能优化案例
    jvm默认的并行垃圾回收器和G1垃圾回收器性能对比
    JVM性能参数优化
    一次压测中tomcat生成session释放不及时导致的频繁fullgc性能优化案例
    sed命令实现文件内容替换总结案例
    You have new mail in /var/spool/mail/root消除提示的方法
    zookeeper常用命令
    mongodb输错命令后不能删除问题
    centos环境gcc版本升级
  • 原文地址:https://www.cnblogs.com/yxlblogs/p/3614275.html
Copyright © 2011-2022 走看看