Dieser Artikel bezieht sich auf den Stand vom 29.08.2008 für Silverlight Version 2, Beta 2. Ich kann nicht garantieren, dass die hier beschriebenen Funktionalitäten so auch in den finalen Versionen Gültigkeit haben, werde aber versuchen, den Artikel halbwegs aktuell zu halten.
Silverlight ist als direkte Konkurrenz-Technologie zu Adobes Flash entwickelt worden. Dabei handelt es sich um sogenannte Rich Internet Applications (RIA), welche mittels Webbrowser aufgerufen und anschließend auf dem Client ausgeführt werden, für die Browser "Firefox" und "Internet Explorer" existieren entsprechende PlugIns. Ruft man eine Silverlight-Seite ohne diese PlugIns auf, erscheint ein entsprechender Hinweis. Klickt man diesen an, wird man auf eine Download-Seite gelenkt, von welcher man sich die entsprechenden PlugIns laden und installieren kann.
Wer mit Silverlight entwickeln will, sollte direkt die
Silverlight Tools Beta 2 for Visual Studio 2008 installieren.
Microsoft hat für Silverlight auch ein eigenes Portal eingerichtet, welches unter
http://silverlight.net/ zu finden ist.
Fertige Silverlight-Anwendungen werden mit allen benötigten Assemblies und Ressourcen in .xap-Dateien verpackt. Dabei handelt es sich um einfache zip-Archive. Die Silverlight-Browser-PlugIns erkennen diese Dateien, entpacken sie und führen die Anwendung aus. xap-Dateien entsprechen somit den war- oder ear-Dateien in J2EE (the hole application in one file). Das Deployment von Silverlight-Anwendungen wird somit sehr stark vereinfacht.
Silverlight-Anwendungen benötigen nicht zwingend einen Webserver (außer natürlich, die Anwendungslogik erfordert dies, z.B. bei Verwendung von oder auch in ASP.NET-Controls). In solchen Fällen reicht eine einfache HTML-Seite zur Anzeige der Silverlight-Anwendung aus. Eine entsprechende Standard-Seite erzeugt Visual Studio 2008 z.B. beim compilieren automatisch und ruft diese Seite beim Projektstart auch im Standard-Browser auf.
Wenn Silverlight-Anwendungen über einen Webserver verfügbar sein sollen und es sich bei der genutzten Umgebung nicht mindestens um Microsoft Windows Server 2008 und IIS 7.0 handelt, ist es erforderlich, den zugehörigen MIME-Type für xap-Dateien (application/x-silverlight-app) zur IIS-Konfiguration hinzu zu fügen.
Zum debuggen einer Silverlight-Anwendung muss der Debugger an den entsprechenden Browser-Prozess angehängt werden (Debug/Attach process).
Networking with Silverlight
Sowohl beim Aufruf von Webseiten als auch bei der Verwendung von Sockets sind einige Dinge zu beachten. Silverlight-Anwendungen laufen in einer Sandbox. Dadurch ist es z.B. nicht möglich, beliebig im Dateisystem des Clients zu arbeiten, lediglich der Zugriff auf einen eigenen Application-Storage ist möglich. Auch der Zugriff auf entfernte Rechner (Cross domain access) ist nicht ohne weiteres möglich, in jedem Fall wird eine Policy-Datei im XML-Format benötigt.
In beiden Fällen wird dabei vor dem Zugriff auch den entfernten Rechner von diesem die o.g. Policy-Datei geladen. Bei WebServern muss diese Policy-Datei dazu im Root-Verzeichnis liegen und mit clientaccesspolicy.xml benannt werden, bei Verbindungen über Sockets wird's etwas umständlicher. Hier muss auf dem entfernten Rechner ein sog. Policy-Server laufen, welcher aber schnell selbst geschrieben ist:
C#-Code: |
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace PolicyServer
{
class PolicyConnection
{
private Socket m_connection;
private byte[] m_buffer;
private int m_received;
private byte[] m_policy;
private static string s_policyRequestString = "<policy-file-request/>";
public PolicyConnection(Socket client, byte[] policy)
{
m_connection = client;
m_policy = policy;
m_buffer = new byte[s_policyRequestString.Length];
m_received = 0;
try
{
m_connection.BeginReceive(m_buffer, 0, s_policyRequestString.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
}
catch (SocketException)
{
m_connection.Close();
}
}
private void OnReceive(IAsyncResult res)
{
try
{
m_received += m_connection.EndReceive(res);
if (m_received < s_policyRequestString.Length)
{
m_connection.BeginReceive(m_buffer, m_received, s_policyRequestString.Length - m_received, SocketFlags.None, new AsyncCallback(OnReceive), null);
return;
}
string request = System.Text.Encoding.UTF8.GetString(m_buffer, 0, m_received);
if (StringComparer.InvariantCultureIgnoreCase.Compare(request, s_policyRequestString) != 0)
{
m_connection.Close();
return;
}
m_connection.BeginSend(m_policy, 0, m_policy.Length, SocketFlags.None, new AsyncCallback(OnSend), null);
}
catch (SocketException)
{
m_connection.Close();
}
}
public void OnSend(IAsyncResult res)
{
try
{
m_connection.EndSend(res);
}
finally
{
m_connection.Close();
}
}
}
class PolicyServer
{
private Socket m_listener;
private byte[] m_policy;
public PolicyServer(string policyFile)
{
FileStream policyStream = new FileStream(policyFile, FileMode.Open);
m_policy = new byte[policyStream.Length];
policyStream.Read(m_policy, 0, m_policy.Length);
policyStream.Close();
m_listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
m_listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, 0);
m_listener.Bind(new IPEndPoint(IPAddress.IPv6Any, 943));
m_listener.Listen(10);
m_listener.BeginAccept(new AsyncCallback(OnConnection), null);
}
public void OnConnection(IAsyncResult res)
{
Socket client = null;
try
{
client = m_listener.EndAccept(res);
}
catch (SocketException)
{
return;
}
PolicyConnection pc = new PolicyConnection(client, m_policy);
m_listener.BeginAccept(new AsyncCallback(OnConnection), null);
}
public void Close()
{
m_listener.Close();
}
}
public class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("usage: PolicyServer.exe PolicyFile.xml");
return;
}
PolicyServer ps = new PolicyServer(args[0]);
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
}
}
|
(Quelle:
Network Security Access Restrictions in Silverlight 2).
Dieser Server wird nun vom Silverlight-PlugIn auf Port 943 mit der Nachricht
XML-Code: |
<policy-file-request/>
|
beehrt, welche dieser mit dem Inhalt der Policy-Datei beantworten muss. Eine beispielhafte XML-Datei könnte so aussehen:
XML-Code: |
<?xml version="1.0" encoding ="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from>
<domain uri="file:///" />
</allow-from>
<grant-to>
<socket-resource port="4502-4506" protocol="tcp" />
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
|
Erst, wenn dieser Vorgang erfolgreich war, darf die Silverlight-Anwendungen auf den entfernten Rechner zugreifen, wobei auch hier eine Restriktion existiert: Es dürfen nur Ports zwischen 4502 und 4534 verwendet werden.
Zudem wurden bei meinen Tests bisher lediglich IPEndPoints als RemoteEndPoints akzeptiert, bei DnsEndPoints wurde keine Verbindung aufgebaut, d.h. Namensauflösung funktioniert anscheinend (noch) nicht.