下午編寫一個Silverlight 與WCF雙工通信Demo時遇到一個10013異常.有一段時間沒有用WCF 費了一點時間.把這個異常給解決掉.其實這個10013異常在WCF中通信算是比較常見.分享一下解決過程以及需要注意的問題.來看一下總體解決方案:
<a href="http://blog.51cto.com/attachment/201201/105013294.png" target="_blank"></a>
如下來說明一下解決方案中項目:
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 應用程式中所允許和不允許的調用示例:
<a href="http://blog.51cto.com/attachment/201201/105021757.png" target="_blank"></a>
這也是Silverlight設計底層資料通信常見跨域問題.在Silverlight 3中已經提出在域的根部署使用正确跨域政策檔案的 Web 服務,可以在其他域中啟用 Silverlight 應用程式要調用的 Web 服務.
Silverlight 應用程式檢測到其請求是一個跨域請求,它将首先在 Web 服務的應用程式根處查找 Silverlight 用戶端通路政策檔案 (clientaccesspolicy.xml)。如果這個請求導緻"404 未找到"或其他錯誤,應用程式将在應用程式根處查找 Adobe Flash 跨域政策檔案 (crossdomain.xml)。不允許重定向跨域政策檔案。此外,對每個應用程式會話隻請求一次跨域政策檔案. 是以首先需要在Service宿主程式上即[ServiceHost]根目錄建立一個跨域政策檔案:
<a href="http://blog.51cto.com/attachment/201201/105030645.png" target="_blank"></a>
檔案内容:
<?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檔案可見:
<a href="http://blog.51cto.com/attachment/201201/105038682.png" target="_blank"></a>
添加完跨域需要支援的政策檔案.需要重新修改WCFLibary項目中WCF Service接口定義.未修改前 需要添加引用using System.ServiceModel.Web引用,有人在網上說自己的.Net版本明明時4.0卻找不到這個這個空間的DLL引用.建議把WCFLibary和ServiceHost宿主程式.Net環境配成一至 如果還有這種情況找不到應該是選擇的是 .Net FrameWork Client Profile 把它切換成.NEt Frame Work4完整版本:
<a href="http://blog.51cto.com/attachment/201201/105049333.png" target="_blank"></a>
即可見到System.ServiceModel.Web引用:
<a href="http://blog.51cto.com/attachment/201201/105057856.png" target="_blank"></a>
IDataSenderService尚未修改前:
[ServiceContract(Namespace = "WCFLibrary") ]
public interface IDataSenderService
{
[OperationContract]
void SendPrintCommand(CommunicationInfor CommandStr);
修改後IDataSenderService接口:
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
如上辨別紅色添加一個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端口通路路徑:
<a href="http://blog.51cto.com/attachment/201201/105105350.png" target="_blank"></a>
把跨域政策檔案clientaccesspolicy.xml拷貝至C:\inetpub\wwwroot 目錄下.測試配置是否成功通過浏覽器通路如下效果及跨域檔案是否配置成功:
<a href="http://blog.51cto.com/attachment/201201/105113404.png" target="_blank"></a>
OK 通路成功 證明政策檔案配置已經成功.運作項目發現異常成功解決.如上是我解決這個異常基本過程和思路.推薦給各位參考.
本文轉自chenkaiunion 51CTO部落格,原文連結:http://blog.51cto.com/chenkai/763797