Javascript跨域调用的问题折腾了我好几天,主要参考了博客园大牛jillzhang的两篇博客
博客中没有提供工程源码下载,我把其中的代码拷下来运行,extjs部分始终取不到数据。
可能Extjs4和WCF都有了一些变化,而这两篇博客比较老,所以运行不了。
经过一些修改(主要是加了WCF配置文件的部分),终于可以运行下面这个Grid分页的例子了。
1. Extjs4 部分的代码
主要有2部分:一部分是html,一部分是js
html部分代码
<!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> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Paging Grid-MHZG.NET</title> <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css" /> <script type="text/javascript" src="extjs/bootstrap.js"></script> <script type="text/javascript" src="extjs/ext-all.js"></script> <script type="text/javascript" src="extjs/locale/ext-lang-zh_CN.js"></script> <script type="text/javascript" src="paging.js"></script> </head> <body> <div id="demo"></div> </body> </html>
js部分代码,即paging.js的代码。其他js和css文件是Ext框架自带的。
Ext.require([ 'Ext.grid.*', 'Ext.toolbar.Paging', 'Ext.data.*' ]); Ext.onReady(function(){ Ext.define('MyData',{ extend: 'Ext.data.Model', fields: [ 'title','author', //第一个字段需要指定mapping,其他字段,可以省略掉。 {name:'hits',type: 'int'}, 'addtime' ] }); //创建数据源 var store = Ext.create('Ext.data.Store', { //分页大小 pageSize: 50, model: 'MyData', //是否在服务端排序 remoteSort: true, proxy: { type: 'jsonp', url: 'http://localhost:4124/Service1.svc/Paging', reader: { root: 'items', totalProperty : 'total' }, simpleSortMode: true }, sorters: [{ //排序字段。 property: 'hits', //排序类型,默认为 ASC direction: 'DESC' }] }); //创建Grid var grid = Ext.create('Ext.grid.Panel',{ store: store, columns: [ {text: "标题", 120, dataIndex: 'title', sortable: true}, {text: "作者", flex: 200, dataIndex: 'author', sortable: false}, {text: "点击数", 100, dataIndex: 'hits', sortable: true}, {text: "添加时间", 100, dataIndex: 'addtime', sortable: true} ], height:400, 520, x:20, y:40, title: 'ExtJS4 Grid 分页示例', disableSelection: true, loadMask: true, renderTo: 'demo', viewConfig: { id: 'gv', trackOver: false, stripeRows: false }, bbar: Ext.create('Ext.PagingToolbar', { store: store, displayInfo: true, displayMsg: '显示 {0} - {1} 条,共计 {2} 条', emptyMsg: "没有数据" }) }) store.loadPage(1); })
其中关键部分即:
proxy: { type: 'jsonp', url: 'http://localhost:4124/Service1.svc/Paging',
type设为jsonp,则使用的Ext.data.ScriptTagProxy这个代理。
url为全路径,表示可以跨域调用。
2. WCF代码部分
Service1.svc
<%@ ServiceHost Language="C#" Debug="true" Service="Service1" CodeBehind="Service1.svc.cs" %>
Service1.svc.cs
using System.ServiceModel; using System.ServiceModel.Web; using System.Text; using System.IO; using System.ServiceModel.Activation; [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class Service1:IService1 { public Stream Paging(string _dc, int start, int limit, int page, string callback) { StringBuilder sb = new StringBuilder(); sb.Append("{'total':1000, 'items': [ "); for (int i = start; i < start+limit - 1; i++) { sb.Append("{ 'title': ").Append("'title").Append(i).Append("',"); sb.Append(" 'author': ").Append("'author").Append(i).Append("',"); sb.Append(" 'hits': ").Append(i).Append(","); sb.Append(" 'addtime':'2011/1/1'}, "); } sb.Append("{ 'title': ").Append("'title").Append(start + limit).Append("',"); sb.Append(" 'author': ").Append("'author").Append(start + limit).Append("',"); sb.Append(" 'hits': ").Append(start + limit).Append(","); sb.Append(" 'addtime':'2011/1/1'} "); sb.Append("] }"); string returnStr = callback + "(" + sb.ToString() + ")"; var 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; } } [ServiceContract(Namespace = "")] public interface IService1 { [OperationContract] [WebGet(BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] Stream Paging(string _dc, int start, int limit, int page, string callback); }
3. WCF配置部分,即Web.config中system.serviceModel部分
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true" httpGetUrl=""/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="jsonServiceBehavior"> <enableWebScript/> </behavior> </endpointBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> <services> <service name="Service1"> <endpoint binding="webHttpBinding" contract="IService1" behaviorConfiguration="jsonServiceBehavior"/> </service> </services> </system.serviceModel>
4. 运行效果
启动上面的WCF服务,根据实际的端口号修改Extjs部分的url,然后打开Extjs部分的html即可。
运行界面如下:
初始化时
换页时
5. 总结
Extjs部分没有什么特别的地方,主要是WCF部分有以下几点需要注意:
- 对于被跨域调用的契约方法,加上[WebGet]atrribute
- 对于被跨域调用的实际类,加上[AspNetCompatibilityRequirements]atrribute
- 对于被跨域调用的服务,配置中必须使用webHttpBinding方式,basicHttpBinding不行。
- 对于被跨域调用的服务,配置中需要关联enableWebScript的behavior。
总体感觉比较麻烦,如果有好的方法,欢迎指出!!