Senior Software-Entwickler, netzkern Technology Evangelist

„Echtzeit“-Kommunikation mit SignalR


Vorwort

Mit SignalR kann man Webseiten um eine Echtzeit-Komponente ergänzen. Sah das Modell bisher vor, dass jeder Browser eines Besuchers immer beim Server nachhorchen musste, ob es irgendwelche Neuigkeiten gibt, haben wir jetzt die Möglichkeit auch vom Server aus Daten auch direkt an den Client zu schicken (Quasi in Echtzeit). Dabei hilft uns der SignalR.
SignalR wurde seit Juli 2011 durch David Fowler und Damian Edwards in ihrer Freizeit entwickelt. Seit Oktober 2012 hat dann Microsoft die Schirmherrschaft übernommen und pflegt und supported den SignalR-Code als Teil ihres Web Stacks
Ganz so vollkommen, wie ich euch das jetzt gerne weiß machen würde, ist diese Welt aber noch nicht. Wenn man sich z.B. mit dem Fiddler einmal die Verbindungen anschaut, die der ein oder andere Browser hier so aufmacht, dann wird man feststellen, dass man quasi einen dauerhaften Download hat:



Der Trick dabei ist, dass die Verbindung vom Server offen gehalten wird. Es wird dem Client (Browser des Besuchers) also nicht mitgeteilt, dass alle Daten übertragen wurden und der Client horcht brav weiter, was denn da noch kommt. Dabei gibt es ein paar Probleme zu umschiffen. Unter anderem erlauben manche Browser nur eine maximale Wartezeit, bis die nächsten Daten kommen und machen ansonsten die Verbindung zu. Doch für solche Problemchen kennt der SignalR eine Lösung. Er schließt einfach die Verbindung und öffnet sie erneut, damit der Countdown von vorne startet. Dies und einige weitere kleine Tricks, machen dem Entwickler das Leben so einfach, dass ich hier einmal einen Einstieg in die Programmierung geben möchte.

Wir starten in unserem Fall mit einem leeren ASP.NET MVC 4 – das klappt natürlich auch mit Webforms entsprechend.

Umsetzung

 


Der SignalR selbst wird als NuGet Package angeboten, was die Installation unglaublich einfach macht. Unter Tools -> Package Manager finden wir die Package Manager Konsole. Alternativ können wir auch einen Rechtsklick auf das Projekt in unserer Solution machen und „Manage Packages“ wählen (für die Leute, denen der UI-Weg lieber ist).



In die Package Manager Konsole geben wir folgendes Kommando ein:

install-package Microsoft.AspNet.SignalR

Daraufhin sehen wir ungefähr folgendes:

 


Was die Konsole hier für uns erledigt ist eine Installation aller zum Betrieb von SignalR benötigten Pakete. 
Nachdem die Installation abgeschlossen ist, öffnet sich eine Textdatei, in der einige Hinweise auf Änderungen für uns stehen, die wir so in unser Projekt übernehmen sollen. Ein Beispiel hierfür ist:

namespace MyWebApplication
{
    public class Global : System.Web.HttpApplication
    {
        public void Application_Start()
        {
            // Register the default hubs route: ~/signalr
            RouteTable.Routes.MapHubs();
        }
    }
}
 

Wir gehen also in die CS Datei unserer Global.asax …
 



Wenn wir diesen Eintrag in unser MVC4 Web machen wollen, werden wir feststellen, dass es bereits einige Zeilen darin gibt:

 

Ganz wichtig ist hierbei, dass das registrieren der Hubs (1) VOR der Übergabe von RouteTable.Routes an die RegisterRoutes Methode (2) stattfindet. Ansonsten können unsere Hubs später nicht gefunden werden.

Das war quasi alles, was wir an bestehendem Code ändern mussten (neben einer kleinen Javascript-Änderung, die ich gleich erwähnen werde). Legen wir also die benötigten Dateien an.

Zuerst einmal ein sog. „Hub“. Das ist quasi die Klasse mit den Handlern, die später unsere Nachrichten auswerten sollen (man könnte fast sagen „unser Service“). Dazu gehen wir einfach in den Dialog für ein neues Item und sollten dieses Template vorfinden „SignalR Hub Class“.



(Sollte das Template nicht vorhanden sein – es wird einfach eine Klasse erstellt, die von „Hub“ ableitet.)


Wenn wir unsere Hub-Klasse haben, sollten wir uns noch unseren Home-Controller und unsere Home-View anlegen, damit wir etwas zum Testen haben. Das ganze sollte dann ungefähr so aussehen:
 


Um die erste Kommunikation mit unserem Hub aufzunehmen, fügen wir im Javascript einige Dateien ein. Ich gehe hier den Weg über die jQuery-Version des SignalRs, da diese auch in der offiziellen Doku verwendet wird.
Sollten wir jQuery noch nicht eingebunden haben, sollten wir dies natürlich noch tun. Danach kommt die jquery.signalr.xxx.js noch dazu und eine Referenz auf „signalr/hubs“. Das ist die Standard-Route, unter der die sog. Proxies erstellt werden. Also quasi die Klassen, die beim Aufruf des Hubs helfen.



Der oben gezeigte Code wartet auf das Beenden des Ladens der Seite (Zeile 8) mit Hilfe von jQuery und ruft danach $.connection.hub.start() auf. Dies ruft das erste Mal das Hub serverseitig auf und baut die Verbindung auf. Das folgende „Done“ ist optional, bietet aber einen Handler, um darauf zu reagieren, sobald die Verbindung steht. (In unserem Fall wird dann einfach ausgegeben „Ich darf jetzt senden“.)
Wenn wir uns das $.connection Objekt einmal näher anschauen, finden wir unser „totalTollesHub“. Etwas weiter oben auf dem Screenshot seht ihr, dass ich meine Hub-Klasse „TotalTollesHub“ genannt habe. Im Javascript ist diese dann genauso verfügbar – wichtig ist nur, dass der Anfangsbuchstabe klein geschrieben wird:
 


Um weitere Aktionen mit unserem Hub vornehmen zu können und nicht immer die ganze Zeile tippen zu müssen, merke ich mir mein Hub in einer Variable namens „meinHub“ und rufe nach dem Aufbau der Verbindung die Methode „nachrichtenHandlerAufDemServer“ auf.



Hierbei gibt es direkt zwei Dinge zu bemerken:

1.) Alle Methoden, die wir serverseitig zur Verfügung haben, stellt uns die Client-Version vom Hub unter „*.server“ zur Verfügung.
2.) Woher kommt eigentlich dieser seltsame Methodenname? Auch hier wieder als Erklärung: Serverseitig im Hub ist eine von mir geschriebene Methode zu finden, die diesen Namen trägt – erneut mit dem einzigen Unterschied, dass der Name im Javascript klein geschrieben wird.


Kaum habe ich die Methode aufgerufen, erscheint auch schon im Breakpoint auf dem Server die von mir übergebene „Hello Server“ Nachricht. Die Parameter stimmen dabei einfach in der Reihenfolge mit dem Client überein.


Um antworten zu können, habe ich serverseitig im Hub ein Objekt, dass sich „Clients“ nennt. Der SignalR bietet mir die Möglichkeiten diese zu gruppieren, direkt anzusprechen oder einfach zu broadcasten (an alle schreiben). Ich schreibe hier eine Nachricht „TADAAAAA“ an alle Clients, die momentan verbunden sind:


Clients.All.nachrichtenHandlerAufDemClient("TADAAAA");


Und auch hier fällt wieder auf, dass ich einfach eine Methode auf dem Client aufrufen kann. Die erstelle ich folgendermaßen:

 
 

Man sieht hier, dass das Hub-Objekt eine Eigenschaft namens „client“ hat. Dies ist ein Objekt in dem der Server nach Methoden zum Aufrufen sucht. Wenn ich also hier eine neue Methode als Eigenschaft dieses Objekts erstelle, kann ich serverseitig einfach auf diese Eigenschaft zugreifen.


Lassen wir es laufen und sehen:



Um jetzt nicht immer Nachrichtenboxen wegdrücken zu müssen, ersetze ich den Client-Teil meines Codes durch diese etwas anspruchsvoller ausschauende Zeile mit einem jQuery-Append. Dies erstellt einfach ein neues Textelement mit dem gegebenen Inhalt – und zwar im body-Bereich meiner Seite. Der Vorteil daran ist, dass sich keine Meldungsboxen blockieren können und ich auch schnell hintereinander Texte ausgeben kann:
 


Zu guter Letzt testen wir einmal das besondere an SignalR. Da wir gerade ein Hub gebaut haben, laufen alle Nachrichten an einem zentralen Ort zusammen. Von diesem Ort aus broadcaste ich momentan meine Nachricht einfach an alle Besucher, die mit mir verbunden sind. Öffne ich also ein Fenster, erscheint meine Erfolgsmeldung – öffne ich dann ein zweites Fenster, erscheint meine Erfolgsmeldung auch darin – aber zusätzlich (da ich meine Erfolgsmeldungen ja an alle bereits anwesenden Besucher der Seite schicke) auch in meinem ersten Fenster noch einmal.
 


Natürlich ist prinzipiell die erste Assoziation dieses Verhaltens „Oh – damit kann man ja einen Chat bauen“. Kann man. Und es ist ganz einfach… aber man könnte z.B. auch mehrere Clients auf diesem Weg synchronisieren, also kollaborative Seiten bauen – oder z.B. eine Support-Software, bei dem ein Team von Mitarbeitern Kunden bei Problemen live auf der Seite unter die Arme greifen könnte. Ich freu mich auf viele spannende neue Seiten ;-).


Kommentare
Es wurden noch keine Kommentare zu diesem Eintrag geschrieben.
Kommentar hinzufügen
Vor und Zuname
E-Mail
E-Mail bei weiteren Kommentaren
Mein Kommentar