由【說說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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM