Montag, März 30, 2009

WCF-PubSub Experiment

PubSub (Publish-Subscribe) kann man sehr gut dort einsetzen, wo eine beliebige Anzahl von Empfängern von Nachrichten existiert. Ab und zu wird PubSub auch als Observer-Pattern bezeichnet. Durch PubSub sollen alle die Interessiert sind, die Informationen der Veröffentlichung (Publish) erhalten. Der Vorgang der Veröffentlichung ist als asynchroner Mechanismus konzipiert, es kann allerdings auch synchron benutzt werden (wird aber nicht empfohlen). Aufgrund der asynchronen Ausführung ist der Einsatz einer Message Queue in vielen Anwendungsszenarien empfehlenswert. Eine Message Queue bringen viele Windows Server Systeme bereits mit (Msmq), so dass meistens keine weiteren Kosten anfallen, alternativ kann auch eine Datenbank verwendet werden.

Binding, die Duplex-Verbindungen unterstützen, sind:

  • WSDualHttpBinding
  • NetTcpBinding
  • NetNamedPipeBinding
  • NetPeerTcpBinding
  • NetTcpContextBinding

Auf der MSDN-Seite ist eine sehr gute Übersicht über die gebräuchlichsten Bindings und deren Fähigkeiten.

Mein Beispiel, hier der Download, ist nicht sehr sinnvoll aber es zeigt die grundsätzlichen Funktionen und einige Problemecken.

Ich habe ein sehr recht einfaches Klassenmodell, es werden simple mathematische Operationen in den Services durchgeführt. Es gibt einen Service zum Addieren und einen zum Multiplizieren. Es gibt 4 Service-Interfaces IMathAddService, IMathMultiplyService, ISubscriptionService und IPublishService. Die ersten beiden Services klammere ich aktuell etwas aus, entscheidend ist der ISubscriptionService bei dem sich alle Aufrufer (Subscriber) registrieren, um über Zustandsänderung/Veröffentlichungen informiert zu werden. In meinem Fall implementieren sowohl die Subscriber als auch der SubscriptionService das IPublishService-Interface. Es wäre nicht notwendig, dass der SubscriptionService das Interface implementiert, es macht es in meinem Fall aber einfacher. Durch die Publish-Methode im SubscriptionService werden die Veröffentlichungen angestoßen. Der SubscriptionService führt Veröffentlichungen allerdings nicht sofort aus, sonder stellt diese in eine Queue, da ich immer schön nacheinander eine Abarbeitung durchführen möchte. Die Queue ist im SubscriberManager mit implementiert, typischerweise würde sich hier ein MessageQueuing-System anbieten.PubSub-Demo class diagrammEs passiert nicht allzu viel in der Anwendung. Es wird zuerst die Endpoint-Konfiguration erstellt und das Binding gesetzt. Ich verwende NetTcpBinding um mit den verschiedenen Services zu kommunizieren. Im nächsten Schritt (Zeilen 12-16) werden die Instanzen der Subscriber-Channel erstellt, diese bekommen als Informationen den InstanceContext, der auf die Instanz des Callback zeigt. Nach der Erstellung der Hosts für meine 3 Services (Zeilen 18-29) werden die beiden Subscriber am Service registriert (Zeilen .31-34). Innerhalb des Using-Blocks wird die eigentlich Abarbeitung durchgeführt. Der Monitor ist meine Arbeitsklasse für die veröffentlichten Nachrichten. Ich wollte auch etwas die Konkurrenzproblematik bei meiner Anwendung zeigen, dazu rufe wird 2 mal hintereinander eine Veröffentlichung ausgeführt und sofort danach die eine weitere Rechenoperation gestartet. Die Mathe-Services speichern immer das letzte Ergebnis und setzen es bei einem Publish-Aufurf auf NaN (Not a Number).

   1: //setup endpoints
   2: EndpointAddress addressAdd = 
   3:     new EndpointAddress("net.tcp://localhost:5554/pubsub/add");
   4: EndpointAddress addressMultiply = 
   5:     new EndpointAddress("net.tcp://localhost:5554/pubsub/mutliply");
   6: EndpointAddress addressPubSub = 
   7:     new EndpointAddress("net.tcp://localhost:5554/pubsub/register");
   8: //binding with duplex support is required! (WSDualHttpBinding, NetTcpBinding, ..)
   9: NetTcpBinding binding = new NetTcpBinding();
  10:  
  11: //create the channels to register the subscribers (link to subscriber interface)
  12: DuplexChannelFactory<ISubscriptionService> duplexAddService, duplexMultiplyService;
  13: duplexAddService = new DuplexChannelFactory<ISubscriptionService>(
  14:     new InstanceContext(new MathAddService()), binding, addressPubSub);
  15: duplexMultiplyService = new DuplexChannelFactory<ISubscriptionService>(
  16:     new InstanceContext(new MathMultiplyService()), binding, addressPubSub);
  17:  
  18: //create all host and start them
  19: ServiceHost hostAdd = new ServiceHost(typeof(MathAddService));
  20: ServiceHost hostMultiply = new ServiceHost(typeof(MathMultiplyService));
  21: ServiceHost hostSubscribe = new ServiceHost(typeof(MemoryPubSubService));
  22: hostAdd.AddServiceEndpoint(typeof(IMathAddService), binding, addressAdd.Uri);
  23: hostMultiply.AddServiceEndpoint(typeof(IMathMultiplyService)
  24:     , binding, addressMultiply.Uri);
  25: hostSubscribe.AddServiceEndpoint(typeof(ISubscriptionService)
  26:     , binding, addressPubSub.Uri);
  27: hostAdd.Open();
  28: hostMultiply.Open();
  29: hostSubscribe.Open();
  30:  
  31: //register!
  32: ISubscriptionService dupAdd = duplexAddService.CreateChannel();
  33: dupAdd.Subscribe(PublishTopics.All);
  34: duplexMultiplyService.CreateChannel().Subscribe(PublishTopics.All);
  35: //run the watcher (async processor)
  36: using (PublishMonitor monitor = new PublishMonitor())
  37: {
  38:  
  39:     ChannelFactory<IMathAddService> addFactory = 
  40:         new ChannelFactory<IMathAddService>(binding, addressAdd);
  41:     ChannelFactory<IMathMultiplyService> multiplyFactory = 
  42:         new ChannelFactory<IMathMultiplyService>(
  43:         binding, addressMultiply);
  44:     IMathAddService add = addFactory.CreateChannel();
  45:     IMathMultiplyService multiply = multiplyFactory.CreateChannel();
  46:  
  47:     Console.WriteLine("Adding 1+2=" + add.Add(1, 2));
  48:     Console.WriteLine("LastResult of add={0}, of multiply={1}", add.GetLastResult(),
  49:                       multiply.GetLastResult());
  50:     Console.WriteLine("Calling publish!");
  51:     //this call should be normally done by the service itself
  52:     dupAdd.Publish(new PublishContext()
  53:                        {
  54:                            Topic = PublishTopics.Add, SomeDetail = "Some one to reset!"
  55:                        });
  56:     dupAdd.Publish(new PublishContext()
  57:                        {
  58:                            Topic = PublishTopics.Multiply, SomeDetail = "Some want's to reset again!"
  59:                        });
  60:     //show some concurrency probs, that can occure
  61:     Console.WriteLine("LastResult of add={0}, of multiply={1}", add.GetLastResult(),
  62:                       multiply.GetLastResult());
  63:     Console.WriteLine("Adding 4*2=" + multiply.Multiply(4, 2));
  64:  
  65:     Thread.Sleep(2000);
  66:     Console.WriteLine("LastResult of add={0}, of multiply={1}", add.GetLastResult(),
  67:                       multiply.GetLastResult());
  68:     Console.WriteLine("Finished sample, Press [Enter]");
  69:     Console.ReadLine();
  70:     Console.WriteLine("closing proxies and hosts");
  71:     addFactory.Close();
  72:     multiplyFactory.Close();
  73: }
  74: //close all and cleanup
  75: duplexAddService.Close();
  76: duplexMultiplyService.Close();
  77: hostSubscribe.Close();
  78: hostAdd.Close();
  79: hostMultiply.Close();

Wird das Ganze ausgeführt, so erhalte ich zum Beispiel auf meinem Dual Core das folgende Ergebnis:

PubSub-Demo output Je nach Lust und Laune des Prozessors kann das Ergebnis der “LastResult of”-Abfragen immer mal etwas anders aussehen, das ist in dem Beispiel von mir durchaus so gewollt, um Probleme der asynchronen Verarbeitung aufzuzeigen.

Perfekt ist die Implementierung meines Beispiels nicht, allerdings soll es auch nur einige Möglichkeiten und Probleme aufzeigen.

Hier noch einige interessante Links zu dem Thema:

Samstag, März 28, 2009

Earth Hour

Heute soll mal wieder ein Zeichen für den Umweltschutz gesetzt werden. Dazu soll jeder heute zwischen 20:30 und 21:30 auf jegliche unnötige Beleuchtung verzichten. Ich werde mich bemühen möglichst viele Verbraucher abzuschalten, allerdings habe ich fast nur Energiesparlampen. Ich hoffe nur, dass unser Stromnetz damit klar kommt, wenn alle plötzlich viel weniger Energie verbrauchen, mal schauen, ob ich auch ein Foto von der Gegend hier zu Stande bekomme.

Ach das Energiesparen wird vermutlich sehr interessant, da auch noch die Lange Nacht des Shoppings ist, also da muss es doch ein besseres Wochenende geben.

Detailierte Informationen erhält man auf der Website von Earth Hour.

Update:

Tja, hier in Lichtenberg hat man von der Earth Hour nix gemerkt, auch in Marzahn ist keine Veränderung zu sehen gewesen. Ich hatte einige Fotos gemacht, aber es ist einfach kein Unterschied zu sehen. Sicherlich ist das Ganze eher ein Symbolischer Akt statt wirklich effektiv einen Nutzen zu haben. Sind nicht auch kleine Gesten wichtig?

Lichtenberg 20:20Lichtenberg 20:33

Sonntag, März 22, 2009

Subversion 1.6 ist da

Noch ein kleiner Beitrag zu guten Tools. Dieses Wochenende wurde außerdem noch Subversion 1.6 und TortoiseSvn 1.6 released. Die interessanteste Neuerung von Subversion Repository Packaging. Interessant wird nun, wann die geeignete Zeit für ein Upgrade unserer Projektumgebungen gekommen ist. Ich gehe davon aus, dass es wie immer ohne größere Probleme abläuft, allerdings die Zeit für das Upgrade (svnadmin upgrade repo) die Komprimierung doch wieder etwas dauert.

PowerShell – gar nicht so schlecht

Ich habe mir ein kostenloses eBook zur PowerShell von Keith Hill besorgt und mich mal ein bisschen damit beschäftigt. Endlich habe ich einiges verstanden und nach einigen Sessions versteht man auch die Zusammenhänge etwas. Die Commands sind noch nicht so drin, wie in der DOS-Batch-Welt. Aber ich habe gelernt, dass das wichtigste Kommando “get-command” ist, danach kommt wahrscheinlich schon “get-member”, dann kann man sich so langsam durch die optionen hangeln. Ab und an hilft vielleicht auch “get-help”, bei “get-help” kommen auch die beiden Kommandos in den remarks als Beispiel.

Für WCF habe ich in der Präsentation von Christian Weyers auch etwas Nettes gefunden “get-wmiobject” oder auch “gwmi”:

   1:   $ms = get-wmiobject -class "AppDomainInfo" -namespace "root\servicemodel" -computername "." | where {$_.Name -eq "myservice.exe"}
   2:   $ms.TraceLevel = "Warning, ActivityTracing"
   3:   $ms.Put()

Für dieses Wochenende reicht es mir aber mit Technikthemen. Ich werde mal versuchen die restlichen Stunden zu nutzen, um endlich wieder fit zu sein.

WCF Tipps und Tricks

Letzte Woche gab es richtig gute Tipps von Christian Weyers zu verschiedenen WCF Themen. Die Folien können die Themen nur Anreisen, aber man bekommt zu dem die Folien und Sample-Code zum Download mit vielen Ressourcen. Jeder der sich mit WCF beschäftigt, sollte sich die Folien reinziehen.

Das ganze Thema Service Throttling habe ich allerdings noch nirgends richtig tiefgehend beleuchtet gefunden. Das Thema ist so komplex und auch service-spezifisch, dass es wahrscheinlich nicht wirklich einfach abzuhandeln geht.

Security gibt es leider gar keine Tipps, aber dafür gibt es andere Quellen und ist wie das Thema Service Throttling einfach extrem umfangreich und auch noch Anforderungsspezifisch.

Donnerstag, März 05, 2009

JavaScript (Frameworks) im Einsatz

Die letzten 2 Monate habe ich mich partiell mit Extrem JavaScript beschäftigt, eigentlich war es auch wieder nicht so extrem. Aber es war die Website mit dem meisten JavaScript, die ich bisher erstellt habe.

Dabei kamen unter anderem auch ComponentArt-Tools zum Einsatz. Im Großen und Ganzen nehmen diese recht viel ab. Allerdings stellt sich wie immer heraus, dass für die speziellen Wünsche ordentlich viel Code notwendig ist.

Das Customizen und Erweitern von Funktionen hat sich durch den Einsatz von jQuery stark vereinfacht, es aber notwendig die Möglichkeiten von jQuery möglichst komplett einzusetzen. Die Standardmöglichkeiten von jQuery sind schon sehr mächtig, hier sind vor allem die Manipulations- und Animationsmechanismen zu nennen. Es passiert leider immer wieder oft, dass man den Selector nicht korrekt angibt. Der Selector ist schon ein riesiges Thema für sich. Ein sehr guter Artikel zu jQuery ist im CoDe-Magazin veröffentlicht, den kann ich nur Empfehlen. Ebenso muss man wirklich die Dokumentation von jQuery loben.

$(<selector>) - $(„#id“) - $(„.cssClass“) – $(„element“)

Die Rückgabe jeder jQuery-Funktion ist ein jQuery-Object. In einem jQuery-Object findet man eine Liste mit den gefundenen Objekten, per Index kann jedes einzelne Zugegriffen werden. Es ist allerdings nicht notwendig auf jedes einzeln zuzugreifen, da jQuery-Funktionen auf alle Elemente in dem aktuellen jQuery-Objekt wirken. Durch $(„p“).css(„color“, „#f00“) erhalten alle p-Elemente die Vordergrundfarbe rot. Am meisten macht das „Spielen“ mit den Effekten Spaß, $(„.ajaxContent“).fadeOut(500,function(){$(this).fadeIn(500);}); - so flackert kurz der Inhalt. Sehr einfach ist es auch einen Parent mit bestimmtem Selector zu finden, hierzu muss die Methode parents verwendet werden. z. B. $(this).parents(<selector>).

Der Zugriff auf Webservices oder WCF-AjaxServices klappt am besten mit den Microsoft ASP.NET AJAX-Funktionen. Dazu muss der ScriptManager auf der Seite verwendet werden und anschließend der Service referenziert werden. 

   1:      <asp:ScriptManagerProxy ID="proxy" runat="server">
   2:          <Services>
   3:              <asp:ServiceReference Path="~/Ausschreibung/GridControl.svc" />
   4:          </Services>
   5:      </asp:ScriptManagerProxy>

Hinweis: JavaScript erlaubt keinen Zugriff auf andere Domains, so dass der Webservice nicht in einer anderen Domain und auch nicht auf einem anderen Server-Port laufen darf.

Außerdem ist noch das Type-System (Stichwort: prototype) mit den im Visual Studio hinterlegten Templates eine tolle Sachen. Es lassen sich mit den Templates recht leicht eigene JavaScript-Klassen erschaffen.

Visual Studio New Item Dialog - Ajax Templates

Etwas mehr nerven hat mich das Thema JavaScript-Events gekostet. Im Gegensatz zu .NET-Events referenziert this nicht das Objekt, dass sich registriert hat, sondern den Sender des Events. Sowohl mit jQuery als auch mit ASP.NET Ajax kann man allerdings die Informationen über den Empfänger (Registrar) mitgeben.

$(<selector>).bind(„click“, <myobject (this)>, function(event){var myobject=event.data});

$addHandlers(element,{click, onClick},myObject);

Jetzt noch einmal zurück zum ComponentArt-Grid, wir wollten eine hierarchische Darstellung des Grids, allerdings ohne auf Ajax zu verzichten. Derzeit unterstützt das Grid im WebService-Mode nur begrenzt diese Funktion. Durch den Artikel im Support-Forum hat es sich lösen lassen. Einige Tipps fehlen allerdings, wie verhält es sich mit Paging, was ist mit Sortierung, was ist mit …. Beim Laden der Objekte müssen diese auch in der Hierarchie der Grid-Level geladen werden. Nach einigen Bugs in meinem Code und einigen kleinen Fehler funktionierte anschließend auch das Paging, dazu ist wichtig, welche Properties gesetzt werden. Hier meine Erkentnisse:

    1. Größe der Seite setzen - grid1.set_pageSize(itemsWithinAPage);

    2. Anzahl der ignorierenden Einträge in der Ergebnismenge - grid1.set_recordOffset(0);

    3. Ergebnisse laden - grid1.load(resultArray);

    4. Setzen der Seitenzahl - grid1.set_pageCount(pagesCount);

    5. Endlich darstellen der Ergebnisse - grid1.render();

Ich musste leider feststellen, dass es gar nicht wichtig ist, wenn die Anzahl der Gesamtentreffermenge gesetzt wird, entscheidend ist das korrekte Setzen der Seitenzahl (Punkt 4)ä Ebenso muss die Property für die „GroupingPageSize“ groß genug sein, da sonst die Ergebnisse ohne Rückmeldung nicht mehr dargestellt werden.