你的位置:首页 > ASP.net教程

[ASP.net教程]ASP.NET MVC 定义JsonpResult实现跨域请求


1:原理

在js中,

2:实现

http://localhost:62203/home/index页面代码如下

@{  Layout = null;}<!DOCTYPE html><html><head>  <meta name="viewport" content="width=device-width" />  <title>Index</title>  <script>  function showMessage(result) {    alert(result.name)  }  </script>  <script src="http://localhost:16308/home/index?callback=showMessage" type="text/javascript"></script></head><body>  <div>   </div></body></html>

主要是这句  

<script src="http://localhost:16308/home/index?callback=showMessage" type="text/javascript"></script>,

可以看到,访问的是不同的站点,并且callback的参数值为showMessage,

http://localhost:16308/home/index代码如下

public ActionResult Index()    {      string callback = this.Request["callback"];      string json="{\"name\":\"server\"}";      this.Response.Write(callback + "(" + json + ")");      return new EmptyResult();    }

根据callback获取函数名,然后将json字符串作为函数参数。

访问页面http://localhost:62203/home/index,效果如下

image

可见,站点localhost:62203从站点localhost:16308获取到了数据。

但是我们看服务端的实现,这也太不美观,也比较麻烦。

public ActionResult Index()    {      string callback = this.Request["callback"];      string json="{\"name\":\"server\"}";      this.Response.Write(callback + "(" + json + ")");      return new EmptyResult();    }

我们想要的是调用一个方法,就能实现跨域了,那如何实现呢。看到Controller有个this.Json方法,类型是JsonResult,我们可以参考这个类。定义一个类JsonpResult,派生于JsonResult,在ExecuteResult方法根据callback获取函数名,然后传入json字符串作为函数参数。

public class JsonpResult : JsonResult  {    public static readonly string JsonpCallbackName = "callback";    public static readonly string CallbackApplicationType = "application/json";    public override void ExecuteResult(ControllerContext context)    {      if (context == null)      {        throw new ArgumentNullException("context");      }      if ((JsonRequestBehavior == JsonRequestBehavior.DenyGet) &&         String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))      {        throw new InvalidOperationException();      }      var response = context.HttpContext.Response;      if (!String.IsNullOrEmpty(ContentType))        response.ContentType = ContentType;      else        response.ContentType = CallbackApplicationType;      if (ContentEncoding != null)        response.ContentEncoding = this.ContentEncoding;      if (Data != null)      {        String buffer;        var request = context.HttpContext.Request;        var serializer = new JavaScriptSerializer();        if (request[JsonpCallbackName] != null)          buffer = String.Format("{0}({1})", request[JsonpCallbackName], serializer.Serialize(Data));//首先根据callback获取获取函数名,然后传入json字符串作为函数参数        else          buffer = serializer.Serialize(Data);        response.Write(buffer);      }    }  }

JsonpResult类有了,但是想在Controller这样使用this.Jsonp,所以为Controller类定义一个扩展方法,

public static class ControllerExtension  {    public static JsonpResult Jsonp(this Controller controller, object data)    {      JsonpResult result = new JsonpResult()      {        Data = data,        JsonRequestBehavior = JsonRequestBehavior.AllowGet      };       return result;    }  }


这是在Controller就可以直接使用this.Jsonp了,把跨域服务端的代码改下
public ActionResult Index()    {      return this.Jsonp(new { name = "server JsonpResult" });    }

相比上面那个简洁多了

再次打开http://localhost:62203/home/index

image

同样,站点localhost:62203从站点localhost:16308获取到了数据,和上面的一样