1

I have a locally hosted WCF service and a silverlight 5 app that communicates with it. By default silverlight tries to obtain the cross domain policy file over HTTP when making calls to the WCF service. I need to change this so that the policy file is served over net.tcp port 943 instead.

I have setup a local tcp listener that serves up the policy file over port 943 and i have followed this technique whereby i make a dummy socket connection in order to obtain the policy file over tcp as it is only retrieved once per application lifetime. The tcp server is being hit as expected and i am getting SocketError property value as Success (though i must note, the first time i hit the tcp server after starting the listener, the result is always access denied).

From what i can tell, the policy file is either invalid as the silverlight application as still unable to connect or the above mentioned technique does not work with silverlight 5.

What i would like to know is if what i am doing is possible & im doing it correctly, otherwise if there is an alternative means to have the policy file successfully downloaded over tcp and removing the need for retrieving it over HTTP.

Thanks

Bablo
  • 906
  • 7
  • 18

1 Answers1

1

I wrote a long post about hosting silverlight in WPF - and using WCF with a http listener here:

How can I host a Silverlight 4 application in a WPF 4 application?

Now while not directly answering your question, it does show how to create a http version of the policy file.

I have also written something that serves up a policy listener over port 943, but I can't find where I posted the source - so I'll keep digging. As far as I remember though, silverlight does a cascade find of the policy file, if it doesn't get a connection on port 80, it'll then look on port 943.

I hope this is of some help somewhere.

Ok, here is the policy listener I had for net.TCP transport i.e. not HTTP based. I presume you have sorted this by now, sorry for the delay. It may well be of use to someone else now.

I was looking for the MS thing that said they cascade from HTTP to TCP, however, I can't, and therefore have to assume it was bunk and then changed.

Either way, if you call using a net.TCP service, and want a listener for it, this code should help:

#region "Policy Listener"

// This is a simple policy listener
// that provides the cross domain policy file for silverlight applications
// this provides them with a network access policy
public class SocketPolicyListener
{

    private TcpListener listener = null;
    private TcpClient Client = null;
    byte[] Data;
    private NetworkStream netStream = null;

    private string listenaddress = "";

    // This could be read from a file on the disk, but for now, this gives the silverlight application
    // the ability to access any domain, and all the silverlight ports 4502-4534
    string policyfile = "<?xml version='1.0' encoding='utf-8'?><access-policy><cross-domain-access><policy><allow-from><domain uri='*' /></allow-from><grant-to><socket-resource port='4502-4534' protocol='tcp' /></grant-to></policy></cross-domain-access></access-policy>";

    // the request that we're expecting from the client
    private string _policyRequestString = "<policy-file-request/>";

    // Listen for our clients to connect
    public void Listen(string ListenIPAddress)
    {
        listenaddress = ListenIPAddress;
        if (listener == null)
        {
            listener = new TcpListener(IPAddress.Parse(ListenIPAddress), 943);

            // Try and stop our clients from lingering, keeping the socket open:
            LingerOption lo = new LingerOption(true, 1);
            listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger,lo);
        }

        listener.Start();

        WaitForClientConnect();
    }

    private void WaitForClientConnect()
    {
        listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), listener);
    }

    public void StopPolicyListener()
    {
        if (Client.Connected)
        {
            // Should never reach this point, as clients
            // are closed if they request the policy
            // only clients that open the connection and
            // do not submit a policy request will remain unclosed
            Client.Close();
        }

        listener.Stop();
    }

    public void RestartPolicyListener()
    {
        listener.Start();
    }

    // When a client connects:
    private void OnClientConnected(IAsyncResult ar)
    {
        if (ar.IsCompleted)
        {
            // Get the listener that handles the client request.
            TcpListener listener = (TcpListener)ar.AsyncState;

            // End the operation and display the received data on 
            // the console.
            Client = listener.EndAcceptTcpClient(ar);

            // Try and stop our clients from lingering, keeping the socket open:
            LingerOption lo = new LingerOption(true, 1);
            Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);

            // Set our receive callback     
            Data = new byte[1024];
            netStream = Client.GetStream();
            netStream.BeginRead(Data, 0, 1024, ReceiveMessage, null);
        }

        WaitForClientConnect();
    }

    // Read from clients.
    public void ReceiveMessage(IAsyncResult ar)
    {
        int bufferLength;
        try
        {
            bufferLength = Client.GetStream().EndRead(ar);

            // Receive the message from client side.
            string messageReceived = Encoding.ASCII.GetString(Data, 0, bufferLength);

            if (messageReceived == _policyRequestString)
            {
                // Send our policy file, as it's been requested
                SendMessage(policyfile);

                // Have to close the connection or the
                // silverlight client will wait around.
                Client.Close();
            }
            else
            {
                // Continue reading from client. 
                Client.GetStream().BeginRead(Data, 0, Data.Length, ReceiveMessage, null);
            }
        }
        catch (Exception ex)
        {
            throw new Exception(Client.Client.RemoteEndPoint.ToString() + " is disconnected.");
        }
    }

    // Send the message.
    public void SendMessage(string message)
    {
        try
        {
            byte[] bytesToSend = System.Text.Encoding.ASCII.GetBytes(message);
            //Client.Client.Send(bytesToSend,SocketFlags.None);
            Client.GetStream().Write(bytesToSend,0, bytesToSend.Length);
            Client.GetStream().Flush();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}
#endregion
Community
  • 1
  • 1
BaconSah
  • 421
  • 3
  • 10
  • I am aware of the HTTP solution and the setup of my application is exactly as described (Silverlight hosted by WPF app). My main problem with that approach is that the WPF application will be likely used by users with "restricted user" accounts where they won't have the necessary rights to start a HttpListener or open a ServiceHost. I have tried programmatically reserving the http URLs at runtime (the ports are only known at runtime) using netsh/httpcfg but even that requires admin rights in process. Do you know a way around this? I also look forward to your 943 solution. – Bablo Apr 03 '13 at 09:58
  • Also if i start a listener/open service host on port 80, would that not interfere with IIS on the local machine (assuming its running)? – Bablo Apr 03 '13 at 10:22
  • I've had to take a different route due to the frustration of not being able to solve this problem. I did use a similar tcp based policy server as you've described in your edited post in a previous attempt to solve this but i still had no luck. I was able to connect to the policy server successfully using sockets but subsequent calls from wcf in silverlight still wanted to retrieve the policy file over http. Maybe its a SL5 thing? In all i decided to use the DOM of the webbrowser control as a proxy between the hosted SL app and WPF as it was a suitable solution for my particular scenario – Bablo Apr 26 '13 at 08:58