Netzwerkzugriffe sind mit Silverlight nicht ohne Tücken. Sogenannte Cross Domain Zugriffe haben schon manchen zur Verzweiflung getrieben. Dann gibt es seit Silverlight 3 zwei verschiedene Netzwerk Stacks den HTTP Client Stack und den HTTP browser Stack. Und beide beherschen keine Authentifizierung nicht mal Basic Clear Text und auch keine Tricks mit manipulierten HTTP header sind möglich. Man erhält höchsten eine not implemented Exception.
Ich hab mich nicht abschrecken lassen und einen Workaround geschrieben. Dafür verwenden ich einfach ASP.NET AJAX aufrufe und Brücke das Ergebnis per Jscript vom Browser in die Siulverlight Anwendung.
Zunächst erstelle ich eine Twitter Account und bschränke den Abruf des RSS Feeds auf “followers”. Das bedeutet das nur registrierte Benutzer die von mir als Follower akzeptiert worden sind den Feed öffnen können. Es erscheint dann ein Login Dialog als Popup.
Im der ASPX Seite muss zuerst das AJAX Scriptmanager Control gezogen werden. Natürlich muss auch das Silverlight Plugin dort gehostet werden. Dies passiert per Object Tag. Wichtig ist auch noch die ID zu setzen. Im folgend als SL1.
Als nächstes geht es um den Jscript Code in der ASPX Seite. Für die Authentifizierung setzt man den HTTP Header. Schon Urzeiten werden die Login Daten in der Form “username:password” übergeben, allerdings codiert als base64. Dieses Beispiel erzeugt von “SilverlightInsi:password” den base64 String. Da Ajax das nicht kann erledige ich diesen Job in der Silverlight Anwendung. Dazu aber später mehr.
function anmelden(user) {
// base 64 =U2lsdmVybGlnaHRJbnNpOnBhc3N3b3Jk
var w = new Sys.Net.WebRequest();
w.set_url("http://twitter.com/statuses/friends_timeline/61248865.rss");
w.set_httpVerb("GET");
w.get_headers()["Authorization"] = "Basic " + user;
w.add_completed(WennFertig);
w.invoke();
}
Jetzt muss das Click Event eines Buttons “laden” in Silverlight auscodiert werden. Mit der htmlpage helper Klasse kann man eine Jscript Methode aus VB oder C# aufrufen. Dieser RSS Downloader Funktion “anmelden” übergebn wir dann die Base64 codierten Benutzer Daten.
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim user As String = "SilverlightInsi"
Dim pwd As String = "password"
Dim daten() As Byte = System.Text.Encoding.UTF8.GetBytes((user + ":" + pwd))
HtmlPage.Window.Invoke("anmelden", Convert.ToBase64String(daten))
Wenn die RSS Daten fertig geladen sind wird die Callback Function “WennFertig” in der ASPX Page aufgerufen. Diese ist eine JScript Methode. Darin werden die RSS Infos im Response zurückgegeben. Nun müssen diese XML Daten aber wieder in die Silverlight Anwendung. Das wird durch den aufruf der Managed Methode “Twitterloaded” durchgeführt. Um Zugriff auf Methoden der Silverlight Anwendung aus JScript zu haben benötigt man eine Referenz auf das Siilverligth Plugin. Dazu wird die ID des Object Tags im DOM Tree gesucht. Über die Eigenschaft “content” und das Objekt sl, kann man schliesslich die Methode aufrufen. Dazu braucht aber die Silverlight Anwendung ein wenig vorbereitung. Wie das geht, lernen Sie ein paar Zeilen weiter.
function WennFertig(executor, eventArgs) {
if (executor.get_responseAvailable()) {
var SL = document.getElementById("sl1");
SL.Content.sl.TwitterLoaded(executor.get_responseData());
}
}
Zurück im manged Code con Silverlight. Das Jscript Proxy Objekt wird Registriert als “sl”. Damit kann Jscript generell auf die Innereien des Plugins zugreifen.
Public Sub New()
InitializeComponent()
HtmlPage.RegisterScriptableObject("sl", Me)
End Sub
Nun brauchen wir noch die managed Funktion auf die von ausserhalb per Jscript zugegriffen wird. Dazu benötigt man das Methodenattribut ScriptableMember. Nun steht die Funktion “Twitterloaded” auch für einen Auruf von aussen zur Verfügung. Nun greife ich noch ein wenig in die Trickkiste um mir Codezeilen zu sparen. Ich verwende die Syndication Klassen von Silverlight. So brauche ich keine RSS Datenklasse oder Liste zu schreiben.
<ScriptableMember()> _
Public Sub TwitterLoaded(ByVal daten As String)
Dim sr As StringReader = New StringReader(daten)
Dim xr As XmlReader = XmlReader.Create(sr)
Dim feed As SyndicationFeed = SyndicationFeed.Load(xr)
datagrid1.ItemsSource = feed.Items.ToList
End Sub
Zuletzt noch der XAML Code. Das SyndicationItem ist kein flacher Datentyp. Man muss also aufpassen das man die richtige Eigenschaft bindet, so z.B. Title.Text. Die Colums werden dann noch manuell definiert.
<data:DataGrid.Columns>
<data:DataGridTemplateColumn Width="200">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title.Text}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTemplateColumn Width="100">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding PublishDate}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
So hübsch sieht dann meine Anwendung aus.
Wenn Sie mehr lernen wollen freue ich mich wenn Sie einen meiner Kurse bei ppedv AG besuchen.