昨天,博客园首页增加了Digg功能。在该功能中我们开始尝试使用jQuery直接调用WCF。之前我们采用的方案是jQuery调用Web Service,然后WebService再调用服务层。这样调用主要是因为之前需要调用不同域名下的WCF服务,因为跨域调用的问题,就要通过Web Service中转一下。而这次Digg功能调用的是同一个应用程序下的WCF,用jQuery直接调用WCF是更好的选择。在尝试这种方式的过程中遇到 的一些问题和一些需要注意的地方需要记录一下,所以就写了这篇随笔。
的给了我们很大帮助,在这里感谢!在探索技术的过程中,将自己解决问题的经验记录下来,不仅可以备忘、总结,而且可以帮助遇到同样问题的朋友,这也是写博客的一种乐趣吧。
进入正题,jQuery调用WCF需要注意的一些问题:
1. WCF的配置(WCF服务宿主于IIS 7)
1)WCF服务相关配置:
在需要调用的接口方法(OperationContract)上加上属性[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)],比如:
[ServiceContract] public interface IDiggService { [OperationContract] [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)] string GetDiggCountList( string entryIdList); } 给服务实现类加上属性:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class DiggService : IDiggService { } 否则调用时会出现错误:“IIS 7.0 Detailed Error - 500.0 - System.ServiceModel.ServiceActivationException”。
2) Web.config中的WCF相关配置:
< system.serviceModel > < services > < service name ="DiggService" > < endpoint address ="" binding ="webHttpBinding" contract ="IDiggService" behaviorConfiguration ="DiggServiceBehavior" /> </ service > </ services > < behaviors > < endpointBehaviors > < behavior name ="DiggServiceBehavior" > < enableWebScript /> </ behavior > </ endpointBehaviors > </ behaviors > </ system.serviceModel > 需要注意两个地方的配置:
a) binding="webHttpBinding",开始设置为binding="basicHttpBinding",出现错误提示:
The endpoint at 'DiggService.svc' does not have a Binding with the None MessageVersion. 'System.ServiceModel.Description.WebScriptEnablingBehavior' is only intended for use with WebHttpBinding or similar bindings.
b) <enableWebScript/> ,启用这个设置才能让WCF支持Ajax调用,否则调用时WCF会返回这样的错误:
The message with To 'DiggService.svc/GetDiggCountList' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.
二、客户端jQuery调用注意
开始按照调用Web Servcie的方式调用:
$.ajax({ url: ' /wcf/DiggService.svc/GetDiggCountList ' , data: ' {"entryIdList":" ' + entryIdList + ' "} ' , type: ' post ' , dataType: ' json ' , contentType: ' application/json; charset=utf8 ' , success: function (data) { if (data.d) { } } }, error: function (xhr) { alert(xhr.responseText); } }); 在FireFox中能成功调用,但在IE 8和Google Chrome中,调用后返回的却是IIS 7的错误信息:IIS 7.0 Detailed Error - 400.0 - Bad Request。
后来将 contentType: 'application/json; charset=utf8' 改为 contentType: 'text/json'问题就解决了。
jQuery调用Web Service与WCF还有一个不同之处在参数格式的处理上:
比如上面代码中的data: '{"entryIdList":"' + entryIdList + '"}',如果将参数名的双引号去掉,即data: '{entryIdList:"' + entryIdList + '"}',可以正常调用Web Service,调用WCF会出现Json反序列化的异常。
三、其他需要注意的地方
如果WCF服务所在的IIS站点中绑定了多个域名, 在没有设置baseAddressPrefixFilters的情况下,会出现错误提示:
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.Parameter name: item
设置好baseAddressPrefixFilters,比如:
< serviceHostingEnvironment > < baseAddressPrefixFilters > < add prefix ="http://www.cnblogs.com" /> </ baseAddressPrefixFilters > </ serviceHostingEnvironment > 这样在访问http://www.cnblogs.com时能正常调用,但访问http://cnblogs.com时调用就出错(IIS 7.0 Detailed Error - 404.0 - Not Found),因为之前的代码中使用的是相对地址调用,实际调用的是http://cnblogs.com/wcf/DiggService.svc /GetDiggCountList,由于设置了baseAddressPrefixFilters,不允许这样调用,只能改为绝对地址(http: //www.cnblogs.com/wcf/DiggService.svc/GetDiggCountList),这样又会造成跨域调用。这个问题目 前还不知如何解决。
四、遗留问题
如何控制缓存,比如:如何在WCF返回时设置Expires Header和If-Modified-Since,避免频繁的WCF调用。
五、总结
jQuery调用WCF的要点:
1. [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
2. [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
3. binding="webHttpBinding"
4. <enableWebScript/>
5. contentType: 'text/json'
参考文章:
1.
2.
相关小组: