[转载]由"说说JSON和JSONP"博文想到的MVC 扩展

[转载]由【说说JSON和JSONP..】博文,想到的MVC 扩展 – DotDot – 博客园.

前言

今天看到随它去吧大牛的 【原创】说说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 
   public class JsonpResult : ActionResult
     {
 
 
         public string Json
         {
             get;
             set;
         }
 
         public string Callback
         {
             get;
             set;
         }
 
         public override void ExecuteResult(ControllerContext context)
         {
             if (context == null)
             {
                 throw new ArgumentNullException("context");
             }
             HttpResponseBase response = context.HttpContext.Response;
             response.ContentType = "application/x-javascript";
 
             if (Callback == null)
             {
                 Callback = context.RouteData.Values["action"].ToString();
             }
 
             response.Write(string.Format("{0}({1})", Callback, Json));
 
         }
     }

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

   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

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏