下午编写一个Silverlight 与WCF双工通信Demo时遇到一个10013异常.有一段时间没有用WCF 费了一点时间.把这个异常给解决掉.其实这个10013异常在WCF中通信算是比较常见.分享一下解决过程以及需要注意的问题.来看一下总体解决方案:
如下来说明一下解决方案中项目:
DeviceEqumentOperater: 这个就是作为WCF服务通信Silverlight Client客户端
DeviceEqumentOperater.Web:Silverlight的Web承载项目
ServiceHost:顾名思义为Service的宿主程序控制项目.
WCFLibrary:WCF Service 编写类库项目,
项目结构比较简单.该项目主要目的是通过Silverlight程序以WCF双工通信方式于设备进行通信.并回发即时设备通讯数据.以Silverlight4搭建版本在发送数据时出现异常:
System.ServiceModel.CommunicationException: Could not connect to net.tcp://localhost:4503/DataSenderService.UserBLD. The connection attempt lasted for a time span of 00:00:00.0781250. TCP error code 10013: 试图以其访问权限所禁止的方式访问套接字。. This could be due to attempting to access a service in a cross-domain way while the service is not configured for cross-domain access. You may need to contact the owner of the service to expose a sockets cross-domain policy over HTTP and host the service in the allowed sockets port range 4502-4534. ---> System.Net.Sockets.SocketException: 试图以其访问权限所禁止的方式访问套接字 |
进一步跟踪堆栈信息发现出现异常代码是在EndInvoke中出现:
- public System.IAsyncResult BeginSendPrintCommand(DataSenderService.CommunicationInfor str,
- AsyncCallback callback, object asyncState) {
- object[] _args = new object[1];
- _args[0] = CommandStr;
- System.IAsyncResult _result = base.BeginInvoke("SendPrintCommand", _args, callback, asyncState);
- return _result;
- }
- public void EndSendPrintCommand(System.IAsyncResult result) {
- object[] _args = new object[0];
- base.EndInvoke("SendPrintCommand", _args, result);
- }
如上标注红色部分在Silverlight生成WCF Service客户端调用时出现异常. 默认情况下Silverlight 支持在同域或源站点上调用 Web 服务。同域意味着调用必须使用同一子域、协议和端口。这是出于安全原因以及防止跨域伪造。下图演示了在使用默认设置的 Silverlight 应用程序中所允许和不允许的调用示例:
这也是Silverlight设计底层数据通信常见跨域问题.在Silverlight 3中已经提出在域的根部署使用正确跨域策略文件的 Web 服务,可以在其他域中启用 Silverlight 应用程序要调用的 Web 服务.
Silverlight 应用程序检测到其请求是一个跨域请求,它将首先在 Web 服务的应用程序根处查找 Silverlight 客户端访问策略文件 (clientaccesspolicy.xml)。如果这个请求导致"404 未找到"或其他错误,应用程序将在应用程序根处查找 Adobe Flash 跨域策略文件 (crossdomain.xml)。不允许重定向跨域策略文件。此外,对每个应用程序会话只请求一次跨域策略文件. 所以首先需要在Service宿主程序上即[ServiceHost]根目录建立一个跨域策略文件:
文件内容:
- <?xml version="1.0" encoding="utf-8" ?>
- <access-policy>
- <cross-domain-access>
- <policy>
- <allow-from http-request-headers="*">
- <domain uri="*"/>
- </allow-from>
- <grant-to>
- <resource path="/" include-subpaths="true"/>
- <socket-resource port="4502-4530" protocol="tcp" />
- </grant-to>
- </policy>
- </cross-domain-access>
- </access-policy>
如上高亮部分为需要注意配置参数.回头看看翻译一下堆栈异常信息:
未能连接到 net.tcp://localhost:4503/Service。连接尝试的持续时间为 00:00:00.3593750。TCP 错误代码 10013: 试图以其访问权限所禁止的方式访问套接字。原因可能是,试图以跨域的方式访问某服务,而该服务的配置不支持跨域访问。您可能需要与服务的所有者联系,以公开通过 HTTP 的套接字跨域策略,并在允许的套接字端口范围 4502-4534 之内承载该服务。 |
Silverlight 3中sl调和网络通信必须要进行跨域验证,但是到了Silverlight 4版本对跨域依赖渐渐放开.Silverlight4 增强网络支持,允许在没有策略文件下支持跨域访问应用.但是内置程序必须在OOB模式下 信任级别elevated trusted. Silverlight 4正式版调用 net.tcp 的WCF,WCF端要在80端口提供 Socket策略文件. 就是如上clientaccesspolicy.xml. 如上节点分别配置部署位置 和开发Socket端口从4502-4530之间.
设置一下文件编译Bin目录下和Console控制台eXE文件可见:
添加完跨域需要支持的策略文件.需要重新修改WCFLibary项目中WCF Service接口定义.未修改前 需要添加引用using System.ServiceModel.Web引用,有人在网上说自己的.Net版本明明时4.0却找不到这个这个空间的DLL引用.建议把WCFLibary和ServiceHost宿主程序.Net环境配成一至 如果还有这种情况找不到应该是选择的是 .Net FrameWork Client Profile 把它切换成.NEt Frame Work4完整版本:
即可见到System.ServiceModel.Web引用:
IDataSenderService尚未修改前:
- [ServiceContract(Namespace = "WCFLibrary") ]
- public interface IDataSenderService
- {
- [OperationContract]
- void SendPrintCommand(CommunicationInfor CommandStr);
- }
修改后IDataSenderService接口:
- [ServiceContract(Namespace = "WCFLibrary") ]
- public interface IDataSenderService
- {
- [OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
- void SendPrintCommand(CommunicationInfor CommandStr);
- }
如上标识红色添加一个WebGet属性即指定访问跨域策略配置文件路劲.在修改WCF接口定义同时也要需要修改APP.Config文件配置.重新配置Service节点:
- <service behaviorConfiguration="WCFLibrary.UpdateDataBehavior" name="WCFLibrary.DataSenderService">
- <host>
- <baseAddresses>
- <add baseAddress="net.tcp://localhost:4508/DataSenderService"/>
- </baseAddresses>
- </host>
- <endpoint address="" binding="netTcpBinding" contract="IDataSenderService" bindingConfiguration="netTcpBindConfig">
- <identity>
- <dns value="localhost"/>
- </identity>
- </endpoint>
- <endpoint address="net.tcp://localhost:4510/DataSenderService/mex" binding="mexTcpBinding" ></endpoint>
- </service>
当然对于Silverlight 在Sock通信商跨域上支持有一种更为见简单方法即时在ISS中设置80端口下可以访问策略配置clientaccesspolicy.xml.即可.实现对Silverlight跨域访问的支持.打开IIS找到Default WebSite 即找到默认的80端口访问路径:
把跨域策略文件clientaccesspolicy.xml拷贝至C:\inetpub\wwwroot 目录下.测试配置是否成功通过浏览器访问如下效果及跨域文件是否配置成功:
OK 访问成功 证明策略文件配置已经成功.运行项目发现异常成功解决.如上是我解决这个异常基本过程和思路.推荐给各位参考.