• 由【说说JSON和JSONP..】博文,想到的MVC 扩展


    前言

    今天看到随它去吧大牛的 【原创】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例 文章,利用JSONP的跨域令人倍感狂喜。于是想,自己动手针对Asp.net MVC 进行一些扩展,让其更好的支持Jsonp。

    关于 JSONP 的详情这里就不介绍了,请看 ——随它去吧: 【原创】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例    

    扩展要点

    1. 默认约定 Callback 方法名为 Action名,当然也可以提供覆盖。
    2. 自定义JsonpResult,让其返回Js文件类型的响应,看过MVC 源码的同学都知道,这其实很简单(请打开MVC 源码中的JavaScriptResult.cs文件查看)。
    3. 为JsonpResult提供Json序列化器。同样参考MVC源码。
    4. 定义一个JsonpController 继承自Controller 方便使用JsonpResult。

    其他:

    除了上面3点外,我还定义了一个JsonpViewResult,故名思议就是可以支持View。

    核心源码

    JsonpResult
     1   public class JsonpResult : ActionResult
     2     {
     3 
     4 
     5         public string Json
     6         {
     7             get;
     8             set;
     9         }
    10 
    11         public string Callback
    12         {
    13             get;
    14             set;
    15         }
    16 
    17         public override void ExecuteResult(ControllerContext context)
    18         {
    19             if (context == null)
    20             {
    21                 throw new ArgumentNullException("context");
    22             }
    23             HttpResponseBase response = context.HttpContext.Response;
    24             response.ContentType = "application/x-javascript";
    25 
    26             if (Callback == null)
    27             {
    28                 Callback = context.RouteData.Values["action"].ToString();
    29             }
    30 
    31             response.Write(string.Format("{0}({1})", Callback, Json));
    32 
    33         }
    34     }

    JsonpResult 里主要是设置Respone 里的 ContentType 类型, 同时判断Callback是否为null ,如果是则表示使用约定:以Action名为回调函数名。

    JsonpViewResult
      public class JsonpViewResult : ViewResult
        {
            public override void ExecuteResult(ControllerContext context)
            {
                base.ExecuteResult(context);
                //if
                //context.HttpContext.Request.UrlReferrer.Host=="YourDomain"
                //return ContentType="text/Html"
                //else:
                HttpResponseBase response = context.HttpContext.Response;
                response.ContentType = "application/x-javascript";
            }
        }

    JsonpViewResult 只需要简单的继承ViewResult  ,让后同样设置返回类型即可。

     public class JsonpController : Controller
        {
    
            protected internal virtual ActionResult Jsonp(string json)
            {
                return new JsonpResult { Json = json };
            }
    
            protected internal virtual ActionResult Jsonp(string json, string callback)
            {
                return new JsonpResult { Json = json, Callback = callback };
            }
    
            protected internal virtual ActionResult Jsonp(object data)
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                return new JsonpResult { Json = serializer.Serialize(data) };
            }
    
            protected internal virtual ActionResult Jsonp(object data, string callback)
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                return new JsonpResult { Json = serializer.Serialize(data), Callback = callback };
            }
    
            protected internal virtual ActionResult Jsonp(object data, string callback, JavaScriptTypeResolver resolver)
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer(resolver);
                return new JsonpResult { Json = serializer.Serialize(data), Callback = callback };
            }
    
            protected internal virtual ActionResult Jsonp(object data, JavaScriptTypeResolver resolver)
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer(resolver);
                return new JsonpResult { Json = serializer.Serialize(data) };
            }
    
            protected internal ViewResult JsonpView(object model)
            {
                return JsonpView(null /* viewName */, model);
            }
    
            protected internal ViewResult JsonpView(string viewName, object model)
            {
                if (model != null)
                {
                    ViewData.Model = model;
                }
    
                return new JsonpViewResult
                {
                    ViewName = viewName,
                    ViewData = ViewData,
                    TempData = TempData
                };
            }
    
    
        }

    JsonpController 对 JsonpResult 和 JsonpViewResult 进行了封装方便使用。

    使用示例

    新建两个MVCApplictiong 项目,我这里为Asp.net MVC 3 的项目

    在第一个项目为本地域,主要进行Jsonp的跨域请求:

    View
    <h2>
        Index</h2>
    <script>
        var GetCustomers = function (data) {
            alert(data[0].Address );
        };
    
    
        var url = "http://localhost:1853/home/GetCustomers";
    
        var script = document.createElement('script');
        script.setAttribute('src', url);
        document.getElementsByTagName('head')[0].appendChild(script); 
    </script>
    
    
    <script>
        var GetCustomer = function (data) {
            alert(data.Address+" "+data.Name+" "+data.ID);
        };
    
    
        var url = "http://localhost:1853/home/Customer/2";
    
        var script = document.createElement('script');
        script.setAttribute('src', url);
        document.getElementsByTagName('head')[0].appendChild(script); 
    </script>
    
    <script>
        var GetPI = function (data) {
            alert(data);
        };
    
    
        var url = "http://localhost:1853/home/Calculate?callback=GetPI";
    
        var script = document.createElement('script');
        script.setAttribute('src', url);
        document.getElementsByTagName('head')[0].appendChild(script); 
    </script>

    第二个项目为远程域,它负责提供请求的数据封装:

    Controller

    Controller
       public ActionResult GetCustomers()
            {
                var customers = new[]{
                     new Customer{ Address="长安街1", Id=1, Name="张三"},
                     new Customer{ Address="长安街2", Id=2, Name="李四"},
                     new Customer{ Address="长安街3", Id=3, Name="dudu"},
                     new Customer{ Address="长安街4", Id=4, Name="DotDot"},
                     new Customer{ Address="长安街5", Id=5, Name="随它去吧"}
    
                };
    
                return Jsonp(customers);
            }
    
    
    
            public ActionResult Customer(int id)
            {
                var customers = new[]{
                     new Customer{ Address="长安街1", Id=1, Name="张三"},
                     new Customer{ Address="长安街2", Id=2, Name="李四"},
                     new Customer{ Address="长安街3", Id=3, Name="dudu"},
                     new Customer{ Address="长安街4", Id=4, Name="DotDot"},
                     new Customer{ Address="长安街5", Id=5, Name="随它去吧"}
    
                };
    
                var customer = customers.FirstOrDefault(c => c.Id == id);
    
                return JsonpView(customer);
    
            }
    
    
            public ActionResult Calculate(string callback)
            {
                var PI = Math.PI;
                return Jsonp(PI, callback);
            }

    Controller中使用了 JsonpViewResult 因此可以对应的建立一个 View视图。在视图里直接指定Callback和Json数据(当然也可以利用绑定)

    @model MvcApplication3.Models.Customer
    @{
        Layout = null;
    }
    GetCustomer( { Address:'@Model.Address', ID:'@Model.Id', Name:'@Model.Name' } )

    一些未考虑的事情

    1、callback 方法为JS全局的

    2、JsonpViewResult仍旧可以扩展成当为本域请求时显示Html,其他域则返回 Js,(可扩展对外服务)

    示例源码:

    https://github.com/IndexKey/JsonpExtengForAsp.net-MVC

  • 相关阅读:
    【Spring】构建Spring Web应用
    【记录】Spring项目转化为Spring Web项目
    【生活工具】你能带我回家么,可能明天要下雨了。
    【Spring】面向切面之AOP
    【Spring】高级装配
    【Linux】Linux学习笔记(完结)
    【Spring】Spring的bean装配
    【Netty】源码分析目录
    【项目实战】多线程环境下正确创建单例
    【环境搭建】使用Jekyll搭建Github博客
  • 原文地址:https://www.cnblogs.com/keyindex/p/2459626.html
Copyright © 2020-2023  润新知