
在前面文章ExtJs与WCF之间的跨域访问已经通过服务端代理的方式解决了ExtJs与WCF跨域访问的问题,那个方案看起来并不怎么优雅,而当我在写过用Restful方式调用WCF进行上传下载后,愕然发现原来WCF支持原生数据(Raw)的返回,这就解决了ExtJs与Wcf之间进行跨域调用中的难题:返回数据必须满足格式。下面根据ExtJs与WCF之间的跨域访问中实现的项目,通过Stream和ContentType的联合使用,返回原生数据给Extjs,从而实现跨域调用。
在前面文章ExtJs与WCF之间的跨域访问已经通过服务端代理的方式解决了ExtJs与WCF跨域访问的问题,那个方案看起来并不怎么优雅,而当我在写过用Restful方式调用WCF进行上传下载后,愕然发现原来WCF支持原生数据(Raw)的返回,这就解决了ExtJs与Wcf之间进行跨域调用中的难题:返回数据必须满足<script>格式。下面根据ExtJs与WCF之间的跨域访问中实现的项目,通过Stream和ContentType的联合使用,返回原生数据给Extjs,从而实现跨域调用。
第一步:在PageGridService.svc后台代码中,添加操作契约GetProductsByPageCorssDomain,代码为:

GetProductsByPageCorssDomain方法
[OperationContract]
[WebInvoke(Method = "*", ResponseFormat = WebMessageFormat.Json,
UriTemplate = "GetProductsByPageCorssDomain?start={start}&limit={limit}&callback={callback}")]
public Stream GetProductsByPageCorssDomain(int start, int limit,string 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 formater = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(PageData<Product[]>));
MemoryStream ms = new MemoryStream();
formater.WriteObject(ms, returnData);
ms.Position = 0;
StreamReader sr = new StreamReader(ms);
string objContent = sr.ReadToEnd();
string returnStr = callback+"("+objContent+")";
sr.Close();
ms = new MemoryStream();
StreamWriter sw = new StreamWriter(ms);
sw.AutoFlush = true;
sw.Write(returnStr);
ms.Position = 0;
WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
return ms;
}
第二步:在项目中创建一个新的htm页面:PageGridCorssDomainWithRow.htm,代码为:

PageGridCorssDomainWithRow.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 type="text/javascript" src="PageGridCrossDomainWithRow.js" charset="gb2312"></script>

</head>
<body>
<h1>
ExtJs+WCF+LINQ打造分页跨域Grid</h1>
<div id="page-grid">
</div>
</body>
</html>

第三步:在项目中创建一个新的js脚本文件:PageGridCrossDomainWithRow.js

PageGridCrossDomainWithRow.js

/**//*
* Ext JS Library 2.1
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/

Ext.onReady(function()
{


var proxy = new Ext.data.ScriptTagProxy(
{
url:'http://127.0.0.1:50643/PageGridService.svc/GetProductsByPageCorssDomain'
});
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();
});
接下来,浏览PageGridCorssDomainWithRow.htm,便可以得到如下运行结果:
两种方案对比:
- 第一种方案要通过服务端WebClient访问WCF服务,然后由ExtJs访问本地代理页面,这样势必造成一些性能损失。而本文的方式,无须架设服务端代理,由ExtJs直接请求WCF,从操作复杂度上,要低一下,理论上也能因此提高一些性能
- 从实现原理上,第一种方式有些背离ExtJs的设计初衷,ExtJS强调用ScriptTagProxy跨域访问数据,但这样对数据格式有一定要求,第一种方案采用绕过拦路虎的方式,通过一个中转将跨域问题化解掉了,虽然效果达到,但毕竟没有充分利用到ExtJs的ScriptTagProxy,而且违背了WCF中的Restful访问方式。
- 上面两点都是说明第一种方案的缺点,本文方案的优点,但在现实中,考虑到可用性,还是建议用第一种方式的。本文这种方式虽然有一定优点,却大大破坏了WCF程序结构,使得WCF服务程序开发难度加大,且以后难于维护,因为一个服务,他的使命不光光针对ExtJs一方的调用,他的消费者可能很多,消费方式也不仅仅局限在Restful上,更多需求可能体现在SOAP方式上,他消费者所在平台也可能是linux,这样事情就变的复杂起来,一个返回stream的操作具有普遍性么?对于其他消费者,stream友好么?而且设置了ContentType是不是对其他消费者有致命影响呢?这些问题都是要考虑的,如果是一个面向大众的服务,考虑到上面的问题,纵是有千万种理由,这种方案还是不可取的。相比较一点点的性能,更有些得不偿失!当然具体情况要具体分析,如果是专门为ExtJs或者其他Ajax设计的,那本文方案就比较合理了。
修改后的项目示例:
【推荐】国内首个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工具