
ExtJs与WCF之间的跨域访问
在上一篇文章中用ExtJs与Wcf交互实现了分页Grid,回复中心有灵犀同学希望能采用跨域访问的方式,这个问题其实也困扰了我很久,本来ExtJS用ScriptTagProxy支持跨域访问的,如果服务端是.aspx的页面文件,也非常好实现,但换作WCF,问题就复杂起来。本文尝试解决这个问题,方案不是很巧妙,但是我对多种方案实验中第一个且是唯一有效的办法。
在上一篇文章<<ExtJs+WCF+LINQ实现分页Grid>>中用ExtJs与Wcf交互实现了分页Grid,回复中心有灵犀同学希望能采用跨域访问的方式,这个问题其实也困扰了我很久,本来ExtJS用ScriptTagProxy支持跨域访问的,如果服务端是.aspx的页面文件,也非常好实现,但换作WCF,问题就复杂起来。本文尝试解决这个问题,方案不是很巧妙,但是我对多种方案实验中第一个且是唯一有效的办法。
首先看一下如何用ExtJs中的ScriptTagProxy跨域访问服务器.aspx页面,不是重点,但与为何此种方法不适用WCF相关,所以也赘述下,项目是上文中的项目,下面是实现步骤:
第一步:还是向网站中添加Service.aspx页面,然后将其代码更改如下:

Service.aspx代码
using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;


namespace ExtJs_Wcf_Linq_PageGrid



{

public partial class Service : System.Web.UI.Page



{

protected void Page_Load(object sender, EventArgs e)



{

int start = Convert.ToInt32(Request.QueryString["start"]);

int limit = Convert.ToInt32(Request.QueryString["limit"]);

string callback = Request.QueryString["callback"];

ProductsDataContext productDbContext = new ProductsDataContext();

IQueryable<Product> res = productDbContext.Product.Select(product => product);

PageData<Product[]> returnData = new PageData<Product[]>();

returnData.TotolRecord = res.ToArray<Product>().Length;

res = res.Skip<Product>(start);

res = res.Take<Product>(limit);

returnData.Data = res.ToArray<Product>();

System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(PageData<Product[]>));


using (System.IO.MemoryStream ms = new System.IO.MemoryStream())



{

serializer.WriteObject(ms, returnData);

ms.Position = 0;

System.IO.StreamReader sr = new System.IO.StreamReader(ms);

Response.Write(callback+"("+sr.ReadToEnd()+")");

}

}

}

}


第二步:创建一个htm页面PageGridCrossDomain.htm,然后将其代码更改为:

PageGridCrossDomain.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>

<title>ExtJs+WCF+LINQ打造分页Grid</title>

<link rel="stylesheet" type="text/css" href="resources/css/ext-all.css" />


<script type="text/javascript" src="adapter/ext/ext-base.js" charset="gb2312"></script>


<script type="text/javascript" src="ext-all-debug.js" charset="gb2312"></script>


<link rel="stylesheet" type="text/css" href="shared/examples.css" />


<script type="text/javascript" src="shared/examples.js" charset="gb2312"></script>


<script src="ScriptTagReader.js" type="text/javascript"></script>


<script type="text/javascript" src="PageCrossDomain.js" charset="gb2312"></script>


</head>

<body>

<h1>

ExtJs+WCF+LINQ打造分页跨域Grid</h1>

<div id="page-grid">

</div>

</body>

</html>

第三步:添加实现跨域分页的脚本文件

PageCrossDomain.js

/**//*

* Ext JS Library 2.1

* Copyright(c) 2006-2008, Ext JS, LLC.

* licensing@extjs.com

*

* http://extjs.com/license

*/


Ext.onReady(function()
{


//创建一个用于访问WCF服务的HttpProxy,且访问方法为GET


var proxy = new Ext.data.ScriptTagProxy(
{

url:'http://127.0.0.1:50643/Service.aspx'

});


var reader = new Ext.data.JsonReader(



{root:'Data',totalProperty :'TotolRecord'},

[



{name: 'ProductID'},



{name: 'Name'},



{name: 'ProductNumber'},



{name: 'MakeFlag'},



{name: 'FinishedGoodsFlag'},



{name: 'Color'},



{name: 'SafetyStockLevel'},



{name: 'ReorderPoint'},



{name: 'StandardCost'},



{name: 'ListPrice'},



{name: 'Size'},



{name: 'SizeUnitMeasureCode'},



{name: 'Weight'},



{name: 'DaysToManufacture'},



{name: 'ProductLine'},



{name: 'Class'},



{name: 'Style'},



{name: 'Weight'},



{name: 'ProductSubcategoryID'},



{name: 'ProductModelID'},



{name: 'SellStartDate'},



{name: 'SellEndDate'},



{name: 'DiscontinuedDate'},



{name: 'rowguid'},



{name: 'ModifiedDate'}

]

);


var store = new Ext.data.Store(



{proxy:proxy,reader:reader}

);


// create the Grid


var grid = new Ext.grid.GridPanel(
{

store: store,

columns: [



{id:'ProductID',header: "编号",width:30, sortable: true, dataIndex: 'ProductID'},



{header: "名称", width:75, sortable: true, dataIndex: 'Name'},



{header: "产品编码", width:75, sortable: true, dataIndex: 'ProductNumber'},



{header: "是否标记", width:75, sortable: true, dataIndex: 'MakeFlag'},



{header: "颜色", width:50, sortable: true,dataIndex:'Color'},



{header: "数量", width:50, sortable: true,dataIndex:'ReorderPoint'},



{header: "单价", width:50, sortable: true,renderer:'userMoney',dataIndex: 'StandardCost'}

],

stripeRows: true,

autoExpandColumn: 'ProductID',

height:400,

width:600,

title:'产品信息',

viewConfig:



{

columnsText:'列',

sortAscText:'升序',

sortDescText:'降序'

},


bbar: new Ext.PagingToolbar(
{

pageSize: 25,

store: store,

displayInfo: true,

displayMsg: '总记录数 {0} - {1} of {2}',

emptyMsg: "没有记录"

})

});


grid.render('page-grid');


//载入


store.load(
{params:
{start:0,limit:25}});


grid.getSelectionModel().selectFirstRow();

});

浏览PageGridCrossDomain.htm,效果图如下:
好,到此用ExtJs跨域调用.aspx的示例已经完成,过程相当简单,效果也比较完美。
但我写此系列的文章,主要目的在于探讨ExtJs与Wcf交互,经过前面几篇的学习,已经对WCF的RestFul和ExtJs的使用有了些皮毛认识,深切体会到ExtJs+Wcf是一种比较不错的编程模型,它与传统的B/S,C/S都不太一样,相比WebForm,它更像是web开发。而且服务的概念也会得以深刻体现,可谓一箭双雕。书写本文之前,我尝试了很多种办法用于ExtJs跨域访问Wcf实现分页Grid,但都没有成功,查阅了ScriptTagProxy的源码方才发现一些端倪,原来ScriptTagProxy是通过动态创建<scipt>的方式实现跨域的,原理可见阿布兄 的一篇文章:利用script标签实现的跨域名AJAX请求(ExtJS),我也不再赘述,下面给出ScriptTagProxy源码中的一个片段:
这段代码中的 url便是要跨域访问的地址,由此可见url返回的信息必须是完全符合<script></script>格式要求的代码,否则将出现javascript错误,我在前期用ScriptTagProxy调用WCF,总是出现莫名错误,便是缘于此。WCF能返回JSON格式的数据,但这样的数据是不符合变量声明要求的,而察看extjs示例中跨域的相应格式为: strCallback1001({..json数据…}),这样一种格式是声明了一个对象变量strCallback1001,而再看看我们可爱的WCF呢,当我们将其ResponseFormat = WebMessageFormat.Json,而返回PageData<Product[]>,他返回的标准的json数据,不符合要求,而返回string,去掉ResponseFormat = WebMessageFormat.Json,然后在服务方法体中用类似Service.aspx得到json数据的办法得到json数据,然后再通过字符串拼接成js变量声明符合格式要求的数据的时候,再看返回,这次可好,前面无缘无故的给WCF加上了<xml …. Type="string">,原来WCF只支持良种编码格式:XML,Json,这时候我就晕了,你说WCF要是支持个ClearText编码格式,那问题不就解决了嘛,唉,没办法,看来想用ScriptTagProxy是不行了。这个问题困扰了我几天。其实此处我觉得WCF是应该有返回ClearText的选项的,不管怎么样,那样更灵活。可没办法,我查了个遍,认识的几个大牛,也问了,都没有确定答案。
上面一段是一些牢骚,既然是牢骚,语法与思路自然有些乱了,但基本上应该说明了ExtJs与WCF跨域交互的障碍了。
下面是我扫除这一障碍的一个笨得不能再笨的方法
第一步:在项目中创建一个页面Proxy.aspx,作为ExtJs与Wcf跨域操作的代理页面。这个页面和ExtJs位于一个位置,并且去除页面中的HTML代码:
后台代码为:

Proxy.aspx.cs
using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.Collections.Specialized;


namespace ExtJs_Wcf_Linq_PageGrid



{

public partial class Proxy : System.Web.UI.Page



{

protected void Page_Load(object sender, EventArgs e)



{

string remoteUrl = Request.QueryString["remote"];

using(System.Net.WebClient wc = new System.Net.WebClient())



{

NameValueCollection nvc = Request.QueryString;

foreach (string key in nvc.Keys)



{

if (key != "remote")



{

if (remoteUrl.IndexOf("?") == -1)



{

remoteUrl = remoteUrl + "?"+key+"="+ nvc[key];

continue;

}

remoteUrl = remoteUrl + "&" + key + "=" + nvc[key];

}

}

string response = wc.DownloadString(remoteUrl);

Response.Write(response);

Response.End();

}

}

}

}


第二步:创建一个ExtJs通过服务代理与Wcf实现跨域交互的htm页面 :PageGridCrossDomainWcf.htm

PageGridCrossDomainWcf.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head>

<title>ExtJs+WCF+LINQ打造分页Grid</title>

<link rel="stylesheet" type="text/css" href="resources/css/ext-all.css" />


<script type="text/javascript" src="adapter/ext/ext-base.js" charset="gb2312"></script>


<script type="text/javascript" src="ext-all-debug.js" charset="gb2312"></script>


<link rel="stylesheet" type="text/css" href="shared/examples.css" />


<script type="text/javascript" src="shared/examples.js" charset="gb2312"></script>


<script src="ScriptTagReader.js" type="text/javascript"></script>


<script type="text/javascript" src="PageGridCrossDoaminWcf.js" charset="gb2312"></script>


</head>

<body>

<h1>

ExtJs+WCF+LINQ打造分页跨域Grid</h1>

<div id="page-grid">

</div>

</body>

</html>


第三步:创建用于ExtJs与Wcf跨域交互的脚本文件:PageGridCrossDoaminWcf.js

PageGridCrossDoaminWcf.js

/**//*

* Ext JS Library 2.1

* Copyright(c) 2006-2008, Ext JS, LLC.

* licensing@extjs.com

*

* http://extjs.com/license

*/


Ext.onReady(function()
{


//创建一个用于访问WCF服务的HttpProxy,且访问方法为GET


var proxy = new Ext.data.HttpProxy(
{

url:'Proxy.aspx?remote=http://127.0.0.1:50643/PageGridService.svc/GetProductsByPage',

method:'GET'

});


var reader = new Ext.data.JsonReader(



{root:'Data',totalProperty :'TotolRecord'},

[



{name: 'ProductID'},



{name: 'Name'},



{name: 'ProductNumber'},



{name: 'MakeFlag'},



{name: 'FinishedGoodsFlag'},



{name: 'Color'},



{name: 'SafetyStockLevel'},



{name: 'ReorderPoint'},



{name: 'StandardCost'},



{name: 'ListPrice'},



{name: 'Size'},



{name: 'SizeUnitMeasureCode'},



{name: 'Weight'},



{name: 'DaysToManufacture'},



{name: 'ProductLine'},



{name: 'Class'},



{name: 'Style'},



{name: 'Weight'},



{name: 'ProductSubcategoryID'},



{name: 'ProductModelID'},



{name: 'SellStartDate'},



{name: 'SellEndDate'},



{name: 'DiscontinuedDate'},



{name: 'rowguid'},



{name: 'ModifiedDate'}

]

);


var store = new Ext.data.Store(



{proxy:proxy,reader:reader}

);


// create the Grid


var grid = new Ext.grid.GridPanel(
{

store: store,

columns: [



{id:'ProductID',header: "编号",width:30, sortable: true, dataIndex: 'ProductID'},



{header: "名称", width:75, sortable: true, dataIndex: 'Name'},



{header: "产品编码", width:75, sortable: true, dataIndex: 'ProductNumber'},



{header: "是否标记", width:75, sortable: true, dataIndex: 'MakeFlag'},



{header: "颜色", width:50, sortable: true,dataIndex:'Color'},



{header: "数量", width:50, sortable: true,dataIndex:'ReorderPoint'},



{header: "单价", width:50, sortable: true,renderer:'userMoney',dataIndex: 'StandardCost'}

],

stripeRows: true,

autoExpandColumn: 'ProductID',

height:400,

width:600,

title:'产品信息',

viewConfig:



{

columnsText:'列',

sortAscText:'升序',

sortDescText:'降序'

},


bbar: new Ext.PagingToolbar(
{

pageSize: 25,

store: store,

displayInfo: true,

displayMsg: '总记录数 {0} - {1} of {2}',

emptyMsg: "没有记录"

})

});


grid.render('page-grid');


//载入


store.load(
{params:
{start:0,limit:25}});


grid.getSelectionModel().selectFirstRow();

});


好了,现在浏览PageGridCrossDomainWcf.htm,效果图如下:
最后,国际惯例,代码示例:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2006-07-05 两个常用的SQL语句拾零