Vor ein paar Tagen hatte ich ein interessantes Gespräch. Thema war ob und wie man eine Kommunikation zwischen Silverlight und WPF realisieren kann. Hier ein Usecase der das ganze etwas greifbarer macht. Eine Silverlight-Anwendung soll in einem WPF-Fenster geladen werden. Die Silverlight-Anwendung liegt auf einem externen Server, die WPF-Anwendung läuft lokal. Welche Möglichkeiten hat man um eine Kommunikation zu realisieren?
Wir haben verschiedene Ansätze besprochen. Mit Hilfe von WCF, oder über JavaScript,… Letztendlich habe ich mich entschieden einen POC für eine Socket – Lösung zu erstellen.
Bevor mich jetzt alle Backendprofis schlagen… es ist ein POC. Der Code ist weder vollständig, noch für den Produktiveinsatz geeignet.
Da wo der Zimmermann das Loch gelassen hat.
Um eine Socket in Silverlight nutzen zu können, benötigt man eine clientaccesspolicy.xml. Aber wo muss die hin? Wir versuchen ja einen Socket auf „localhost“ zu öffnen. Die Dokumentation sagt dazu folgendes
„To deploy a security policy file on a server for sockets, system administrators need to configure a separate authentication service on port 943 for each IP address that is to provide the policy file definition.”
Zum Glück findet man einen guten Beispielcode hier in der MSDN.
Jetzt muss also noch das Policy File erstellt werden. Für Testzwecke ist folgende Policy Sicher genug.
[xml] <?xml version="1.0" encoding="utf-8"?> <access-policy> <cross-domain-access> <policy> <allow-from http-methods="*"> <domain uri="*"/> </allow-from> <grant-to> <socket-resource port="4502-4506" protocol="tcp" /> </grant-to> </policy> </cross-domain-access> </access-policy> [/xml]
In der realen Welt sollte man diese Einstellung nicht nutzen. Außer man will auf Teufel komm raus ein riesen Loch bauen….
Socket öffne dich
Nachdem jetzt die Rechte ausgehandelt sind kommen wir zum eigentlichen Vorhaben.
Silverlight in Version 3 beherrscht nur TCP Sockets. Nur Sockets über die Ports 4502-4534 sind erlaubt.
Heißt wir müssen im WPF-Host einen TCP Socket auf Port 4502 erstellen, diesen auf “localhost“ binden und warten bis jemand anfragt.
[csharp] public SockedServer(int port) { socket = CreateListeningSocket(AddressFamily.InterNetwork, IPAddress.Any, 5402); if (socket != null) { socket.BeginAccept(new AsyncCallback(HandleConnection), null); } } private static Socket CreateListeningSocket(AddressFamily family, IPAddress adress, int port) { Socket socket; try { socket = new Socket(family, SocketType.Stream, ProtocolType.Tcp); socket.Bind(new IPEndPoint(adress, port)); socket.Listen(10); } catch (Exception) { socket = null; } return socket; } [/csharp]
Im Silverlight müssen wir einen Socket zum „localhost“ auf Port 4502 öffnen und anklopfen.
[csharp] private void OpenSocket() { _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var ep = new DnsEndPoint("localhost", 4503); var args = new SocketAsyncEventArgs { RemoteEndPoint = ep }; args.Completed += HandleConnected; _client.ConnectAsync(args); var dataToSend = Encoding.UTF8.GetBytes("Hallo World."); var args = new SocketAsyncEventArgs(); args.SetBuffer(dataToSend, 0, dataToSend.Length); _client.SendAsync(args); } [/csharp]
Den kompletten Source gibt es hier.
Socket.zip
Über ein Feedback würde ich mich freuen