2

试图调用WCF通过Silverlight的一个NetTcpBinding的,我得到的错误:Silverlight的WCF NetTcpBinding的问题

“TCP错误代码10013:试图通过其访问权限不允许的方式来访问一个插座..这可能是因为尝试以跨域方式访问服务,而服务未配置为跨域访问。您可能需要联系服务的所有者以通过HTTP公开跨域策略套接字并将该服务托管在允许的套接字端口范围4502-4534中。“

我的WCF服务托管在IIS7,势必:

http://localhost.myserivce.com端口80 和的net.tcp端口4502

我可以看到,如果http://localhost.myserivce.com/myservice.svc我浏览到它(我的hosts文件指向这个域到localhost)。 我还可以看到http://localhost.myserivce.com/clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8"?> 
<access-policy> 
    <cross-domain-access> 
     <policy> 
     <allow-from http-request-headers="*"> 
      <domain uri="*" /> 
     </allow-from> 
     <grant-to> 
      <socket-resource port="4502-4534" protocol="tcp" /> 
     </grant-to> 
     </policy> 
    </cross-domain-access> 
</access-policy> 

我在做什么错?

回答

1

如果您尝试在端口范围4502-4534中建立TCP连接,Silverlight将首先在端口943上发布请求以检索客户端访问策略文件内容 - 它不会读取http://localhost.myserivce.com/clientaccesspolicy.xml处的文件,因为这是仅用于HTTP请求。 您需要将服务器配置为侦听TCP端口943,期望请求字符串等于<policy-file-request/>并回复xml文件内容。

下面的代码显示了一个基本的实现,您需要使用端口943来传递给本地IPEndPoint:

public class SocketPolicyServer 
{ 
    private const string m_policyRequestString = "<policy-file-request/>"; 
    private string m_policyResponseString; 
    private TcpListener m_listener; 
    bool _started = false; 

    public SocketPolicyServer() 
    { 
     m_policyResponseString = File.ReadAllText("path/to/clientaccesspolicy.xml"); 
    } 

    public void Start(IPEndPoint endpoint) 
    { 
     m_listener = new TcpListener(endpoint); 
     m_listener.Start(); 
     _started = true; 
     m_listener.BeginAcceptTcpClient(HandleClient, null); 
    } 

    public event EventHandler ClientConnected; 
    public event EventHandler ClientDisconnected; 

    private void HandleClient(IAsyncResult res) 
    { 
     if(_started) 
     { 
      try 
      { 
       TcpClient client = m_listener.EndAcceptTcpClient(res); 
       m_listener.BeginAcceptTcpClient(HandleClient, null); 
       this.ProcessClient(client); 
      } 
      catch(Exception ex) 
      { 
       Trace.TraceError("SocketPolicyServer : {0}", ex.Message); 
      } 
     } 
    } 

    public void Stop() 
    { 
     _started = false; 
     m_listener.Stop(); 
    } 

    public void ProcessClient(TcpClient client) 
    { 
     try 
     { 
      if(this.ClientConnected != null) 
       this.ClientConnected(this, EventArgs.Empty); 

      StreamReader reader = new StreamReader(client.GetStream(), Encoding.UTF8); 
      char[] buffer = new char[m_policyRequestString.Length]; 
      int read = reader.Read(buffer, 0, buffer.Length); 

      if(read == buffer.Length) 
      { 
       string request = new string(buffer); 

       if(StringComparer.InvariantCultureIgnoreCase.Compare(request, m_policyRequestString) == 0) 
       { 
        StreamWriter writer = new StreamWriter(client.GetStream()); 
        writer.Write(m_policyResponseString); 
        writer.Flush(); 
       } 
      } 
     } 
     catch(Exception ex) 
     { 
      Trace.TraceError("SocketPolicyServer : {0}", ex.Message); 
     } 
     finally 
     { 
      client.GetStream().Close(); 
      client.Close(); 
      if(this.ClientDisconnected != null) 
       this.ClientDisconnected(this, EventArgs.Empty); 
     } 
    } 
} 
4

这种情况已经改变为SL4 RTM的。 SL4的net.tcp客户端不会在tcp 943上查找客户端访问策略,而是会使用旧的方法来使用web服务器的根,端口80.奇怪的是,这在任何地方都没有很好的记录,但我可以确认这是发布的行为。

底线,从SL4 RTM开始,您描述的方法应该可行,而其他答案则不适用。