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.

Freitag, Februar 13, 2009

SQL Server 2008 Setup issue Vista x64

Die Woche habe ich mich nach einigen Erzählungen von einem Kollegen dazu entschlossen, die SQL Server 2008 Management Tools zu nutzen. Nach der Entscheidung gleich zu MSDN-Seite und das ISO (Dev-Version) gezogen, leider braucht das bei 4GB einiges an Zeit, wenn man nicht gerade am Deutschen Forschungsnetz hängt.

Den nächsten Tag habe ich dann mit der Installation los gelegt, alte Version der Management Tools deinstalliert, noch relativ Problemlos. Allerdings haben mich die ganzen verbleibenden “Leichen” und Reste etwas verwundert. Ich frage mich immer noch, was weiter zu deinstallieren ist. Anschließend das DVD-Image gemounted und die Installation gestartet. Überraschung, wieder eine neue Installer-Version, dabei fand ich die alte gar nicht schlecht, aber wie auch immer, mutig durch. Dann ging es los!

“Attribute do not match … “-Error nach der Auswahl der Komponenten. Der Fehler bezog sich auf das Zielverzeichnis des SQL Servers. Ok, so überrascht war ich allerdings von dem Fehler nicht, da ich den gleichen Fehler bereits von der SQL Server 2005 Installation kenne. Es ist nicht möglich den Server in komprimierten Verzeichnissen zu installieren. Also ohne Bedenken das Verzeichnis von der Komprimierung ausgenommen und erneut versucht. AH, immer noch der Fehler. Bei meinem 2. Versuch mit etwas verzogener Miene habe ich auf meinen gesamten “Program Files”-Verzeichnis die Komprimierung entfernt, wehe einer hat eine zu kleine Platte. Aber auch der Versuch scheitert. Installation neu gestartet, allerdings keine Besserung. Anschließend habe ich die Installation den Tag über nicht mehr angefasst und sie stand noch im gleichen Zustand. Abend mal so mögliche Optionen überlegt, auch Google bemüht (ich weiß, eigentlich hätte ich Live-Search verwenden müssen), allerdings waren die Texte nicht sehr hilfreich. Dann habe ich etwas probiert, was ich bei einer Microsoft Installation von einer x64-Software nicht erwartet hätte, es funktionierte. Die Lösung war einfach die Attribute vom “Program Files (x86)”-Verzeichnis zu löschen. Aber wo zur Hölle steht denn dieser Tipp!

Nach wenigen Minuten war die Installation abgeschlossen und die Tools ready. So, welchen Server migriere ich nach 2008? ….

Mittwoch, Februar 04, 2009

WPF data binding sheet

Wow, bin gerade auf ein sehr schönes data binding sheet zu WPF gefunden. Der Original post ist hier http://www.nbdtech.com/blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx zu finden. Ich habe mir das Dokument, ca. 300kbyte, gleich mal heruntergeladen und komme damit vielleicht noch besser mit dem data binding zu recht.

Montag, Januar 26, 2009

Continuous Integration – Lohnt meistens

Ich bin ein großer Fan von Continuous Integration (CI) und ich bin auch der Meinung, dass es sich meistensimmer auszahlt. Umso schöner, wenn sich bei Projekten der Erfolg relativ schnell herausstellt und auch andere die Vorteile erkennen. In einem meiner aktuellen Projekte habe wir letztes Jahr mit relativ wenig Überzeugungsarbeit CI mit CCNet eingeführt. Der Initiale Aufwand hielt sich in Grenzen, wahrscheinlich überalles bei 3-4PT (mit Einführung und Lernphase von Kollegen). Der Hauptgrund für die Einführung war erst mal Nachvollziehbarkeit und eindeutige Identifizierung von Versionen. Nach dem dieses Ziel erreicht ist, stellen wir gerade bei unseren häufigeren Patch-Bereitstellungen für Tests fest, wie schön es ist ein CI-System zu nutzen. Das System deployed nun aktuelle Testversionen schnell auf unseren Testserver, das ganze ist noch nicht perfekt, aber das muss es auch nicht sein.

Allerdings merke ich auch immer wieder, wie wichtig es ist, dass mindestens die wichtigen Personen im Projekt einen nutzen sehen und wenn es auch die politischen Dinge, wie Governance, Nachvollziehbarkeit, …. sind. Im Projekt haben wir keine strengen Restriktionen, daher sind viele Prüfungen nur als Informationen ausgeführt und werden auf der Seite reported (Emails lassen wir auch weg.). CI ist als integraler Bestandteil des Entwicklungsprozess zu sehen und erfordert nicht DEN großen Aufwand. Für Neulinge auf dem Gebiet kann ich CI-Factory empfehlen, dass auch eine Best-Practice Verwaltungsstruktur aufsetzt. Ich habe den Focus auf MS-Projekte und Tools, aber CI gibt’s für alle.

Hier noch mal meine Meinung zu den Steps, die im Build-System ablaufen sollten:

  1. Version-Bezeichnung bereitstellen
  2. Validieren der Quellen/ Integration (MSBuild)
  3. Unit-Testen der Quellen (NUnit oder XUnit)
  4. Statische Code-Analyse und Prüfung der Richtlinien (FxCop)
  5. Paketieren und/oder bereitstellen der SW (Wix oder XCOPY)
  6. Markieren (Labeln oder Taggen) der Version in der Quellcodeverwaltung

Gerade die Schritte 1, 2, 4, 5 und 6 sind einfach umzusetzen und bringen auch schnell einen Erfolg. Richtig klasse wird es, wenn das ganze Team den Nutzen erkennt und gerade für Continous Builds zur Verifikation der Quellen nutzt. Hierfür sind Entwicklungsrichtlinien und er gemeinsame Konsens erforderlich und alle müssen in das System schauen. Irgendwo gab es mal das nette Zitat „If you broke it, fix it!“, so muss das Motto jedes Teams heißen.

Leider habe ich immer wieder das Gefühl, dass Projektleiter am wenigsten von sowas zu überzeugen sind. Die meisten Projektleiter achten auf das Budget und können natürlich 3PT zusätzlich nicht verkraften, außerdem erfordert Governance Arbeit. Ich muss noch deutlich an meiner Argumentation arbeiten, aber Freizeit opfern ist nicht.

Sonntag, Januar 18, 2009

Resharper im Einsatz

Im moment teste ich gerade mal für mich den Resharper. Es handelt sich dabei um ein VS-Addin mit unheimlich vielen Funktionen und Möglichkeiten. Den Resharper gibt es als Testversion für 30 Tage zum testen, so dass man es beliebig ausprobieren kann.

Die Installation und der Start waren recht unkompliziert, einzig, dass überschreiben aller meiner Key-Bindings fand ich nicht gut. Zum Glück hatte ich noch eine Sicherung meiner IDE-Settings. Die Arbeit ist prinzipiell sehr einfach und man merkt schnell die ersten Features, abgewandeltes Syntax-Highlighting und die veränderte Intellisense-Hilfe. Außerdem ist es nett, wenn das Tool den Namen der Variablen vorschlägt.

Momentan bin ich recht angetan von den vielen Funktionen, aber andererseits nutzt man nicht alles Features der Suite. Wenn es auch die nächsten Wochen halbwegs so weiter geht beim Arbeiten, dann werde ich die Lizenz bei meinem Chef beantragen.

Dienstag, Dezember 30, 2008

Happy New Year

Ich habe meinen Urlaub gut überstanden, auch die vielen Stunden Flug. Es war wirklich sehr erhohlsam, manchmal etwas langweilig und merkwürdig so alleine. Aber immerhin, ich habe 2 Wochen ohne Rechner durchgehalten und den Rechner erst am 2. Weihnachtsfeiertag benutzt. Ich habe auch einige Bilder gemacht, die wenigsten von mir. ;)

Das Jahr war wirklich anstrengend, es gab richtig viel zu tun und immer kam auch eine Baustelle zu den falschen Zeitpunkten hinzu. Ich habe dieses Jahr nicht sehr viel Urlaub gehabt, was sich nächstes Jahr deutlich zeigen wird.  Leider ist aufgrund der Arbeit auch das bloggen ab und an zu kurz gekommen. Dafür hatte ich aber viele spannende Projekte, Projekte mit den neuen Technologien WCF, WF, LINQ und MVC. Ich hoffe, dass es auch im nächsten Jahr richtig spannend weitergeht. Am Anfang hört sich das schon sehr spannend an mit den 2+ Projekten.

Privat kann ich mich eigentlich an nicht viel erinnern, ich glaube, so wenig habe ich noch nie gemacht. Für mich war das auch gut so, ich habe noch immer an meine Ex gedacht und selbst jetzt ist sie noch nicht aus dem Kopf. Aber ich habe sehr gut Freunde, die mich immer wieder aufheitern.

Auf jeden Fall wünsche ich allen ein gesundes, erfolgreiches, lustiges und glückliches Jahr 2009. Ich hoffe, dass ich im nächsten Jahr wieder reichlich interessante Themen zum bloggen habe und auch dazu komme alles abzuhandeln. Leider war das in diesem Jahr nicht immer so.

Happy Year2009

Sonntag, Dezember 14, 2008

Ab in den Urlaub

Ich verschwinde in den Urlaub, nur noch wenige Stunden bis der Flieger startet. Ich habe die letzten Monate aber auch deutlich gemerkt, dass es bitter notwendig ist. Und so bin ich einfach nur froh, dass das Jahr überstanden ist.

Die nächsten Wochen findet ihr mich in der Dominikanischen Republik ohne jegliches Computer Equipment. Das wird mir schwer fallen, viele Tage ohne Rechner. Aber vielleicht trösten mich die Einheimischen.


View Larger Map

Weihnachtslied

(Ernst Moritz Arndt 1769-1860)

Erklinge, Lied, und werde Schall,
Kling gleich der hellsten Nachtigall,
Kling gleich dem hellsten Lerchenklang
Die ganze, weite Welt entlang.

Kling, Lied, und kling im höchsten Ton:
Es kommt der süße Gottessohn,
Es kommt das helle Himmelskind
Hernieder, wo die Sünder sind.

Er kehrt bei einer Jungfrau ein,
Will eines Weibes Säugling sein,
Der große Herr der ganzen Welt,
Ein Würmlein auf die Erde fällt.

Ein armes Knäblein nackt und bloß,
So liegt er in Marias Schoß;
Der alle Sterne lenken kann,
Fleht eines Weibes Gnade an.

Der eh'r als Erd' und Himmel war,
Das Wort des Vaters rein und klar,
Spricht lieb und freundlich bei uns ein
Und will der Sünder Bruder sein.

So kommt die unermeßne Huld,
Zu tragen unsre schwere Schuld,
Die ewige Liebe steigt von Gott
Zu uns herab für Schmach und Spott.

Des solln wir alle fröhlich sein
Und singen mit den Engelein
Und singen mit der Hirten Schar:
Das ew'ge Heil wird offenbar.

Des solln wir alle fröhlich sein,
Daß Gott will unser Vater sein,
Und daß der süße Jesus Christ
Heut unser Bruder worden ist.

Schönes Fest!

Sonntag, Dezember 07, 2008

Technical Summit 2008 - Nachtrag

Ich bin ein ganzes Stück verspätet, hier sind aber endlich einige Details/Eindrücke vom Technical Summit.


Windows Live Spaces

Der Technical Summit war interessant und auch aufschlussreich in vielen Bereichen. Von einigen Vorträgen war ich sehr enttäuscht und andere fand ich wieder sehr Klasse. mein Fokus lag auf Parallel Computing und ASP.NET/WCF. Parallel Computing war zu allererst nicht auf der Agenda, da die Key-Note soviel Laune auf mehr gemacht hat, habe ich mir weitere Detail reingezogen. Alles zu Parallelisierung und Microsofts arbeit gibt es auf den Seiten der MSDN. Ich empfehle einfach mal die Parallel Extensions auszuprobieren, es ist sehr einfach seine Anwendung zu modifizieren.

Die Vorträge zu Azure und Cloud Computing fand ich nicht so doll. Hier ist einfach nur alles schwammig, es gibt nichts konkretes und viele Unternehmen, werde wohl nicht sensible Daten außer Haus geben wollen. Ich bin sehr gespannt, wie die Entwicklung im nächsten Jahr weiter geht.

Richtig schlecht fand ich den Vortrag zu ASP.NET-Future, hier war sicherlich auch meine Erwartungshaltung überzogen. Aber es wurde auf so vieles nicht eingegangen, an Themen vorbei geredet und unwesentliches Langgezogen und wesentliches völlig verschluckt. Schließlich wollte der Redner nur noch weg und hat einfach extrem zeitig Schluss gemacht. Der Erfahrungsgehalt des Vortrags war gleich null.

Spass gemacht haben auf jeden Fall die Vorträge von Darius Parys. Es ist sicherlich eine eigenwillige Vortragsart, aber sehr passend für Entwickler.

Technorati-Tags: ,

Visual Studio 2008 - jQuery support

Microsoft hat vor 2 Wochen die Unterstützung für jQuery released. Eine Anleitung für die Installation und Konfiguration des Visual Studio gibt es mal wieder von Scott Guthrie.

Zusammengefasst, muss man folgendes machen:

  1. SP1 für VS2008 installieren
  2. "-vsdoc.js"-Support installieren
  3. jQuery downloaden inkl. Doku und zur Anwendung hinzufügen
  4. Have fun!

Ich bin mir derzeit nicht sicher. ob ich jQuery oder die ASP.NET-Ajax-Komponenten nutzen soll. Ein bisschen überschneiden sich beide Frameworks. Daher werde ich wohl ein einem nächsten Projekt jQuery intensiver nutzen. Ich hatte es bereits in einer Anwendung vor einem halben Jahr drin, habe es dann aber entfernt, da ich nicht 2 Frameworks verwenden wollte.

Jeder der mit Javascript umgeht, sollte sich jQuery einmal anschauen, ob es nicht vieles vereinfacht. ("$"-Operations, ...) Auch bei der Sharepoint-Entwicklung und allen anderen ASP.NET-Projekten kann das Framework eine Menge vereinfachen.

So, nun mal schauen, ob ich noch ein bisschen an meinem Technical Summit Post arbeite. ;)

Sonntag, November 02, 2008

Compression over WCF-Transports

Ich habe mich die letzten Wochen/-enden mit Komprimierung von WCF-Daten beschäftigt. Komprimierung könnte gerade bei der Anbindung von vielen Clients im WAN Bereich positive Ergebnisse erzielen. Im lokalen Bereich schadet es bei heutigen Prozessoren sicherlich wenig und für große Datenmengen ist es in diesen Fällen ideal.

Ich war allerdings nicht so verrückt mich auf eine Neuentwicklung einzulassen. Es musste so etwas bereits geben und so war es auch. In den WCF-Samples ist ein Beispiel enthalten, dies soll vor allem das erstellen von eigenen WCF-Transports demonstrieren. Mit der Lösung habe ich etwas herum gespielt, allerdings habe ich nur eine http-Transport damit zum laufen bekommen. Auf der Suche nach alternativen bin ich auf das CodePlex-Project WCF-Extensions gestoßen. Das Projekt hat bisher kein Release veröffentlicht, allerdings kann man den Code downloaden.

Statt den Code auszuprobieren, habe ich erst mal den Code erweitert. Ich habe zusätzlichen Komprimierungsalgorithmus hinzugefügt, so dass es nun ganze 5 Möglichkeiten gibt.

   1:  public enum CompressionAlgorithm
   2:  {
   3:      GZip,
   4:      Deflate,
   5:      BZip2,
   6:      Zip,
   7:      GZip2
   8:  }

Die letzten 3 Algorithmen verwenden die SharpZibLib zur Komprimierung. Ich finde die ZibLib eine super Implementierung, wer es noch ausgefallener/besser möchte kann dies auch noch um Xceed Zip for .Net aufbohren.

Nach den Anpassungen habe ich zumindest mal einige Tests mit dem integrierten Client gemacht. Es hat sich schnell gezeigt, dass geringe Datenmengen, < 200 Bytes, durch die Komprimierung sogar minimal vergrößert wurden. Die besten Ergebnisse habe ich immer mit BZip2 erhalten. Einen genauen Vergleich der Komprimierungsraten und der Verhalten im WCF-Streams habe ich nicht bis zu Ende durchgeführt. Mir hat es gereicht, nach dem es funktionierte.

So, nun aber zum schwierigeren Teil, die Konfiguration in der app.config. Ich hatte mich eine ganze Weile durch verschiedene MSDN-Pages gesucht und die Konfiguration zusammen zu frickeln. Ich bin froh, dass beim Startup der Anwendung die Konfiguration geprüft wird. Meine erste Konfiguration sah wie folgt aus:

   1:    <system.serviceModel>
   2:      <extensions>
   3:        <bindingElementExtensions>
   4:          <add name="compression" type="WcfExtensions.ServiceModel.Configuration.CompressionElement, WcfExtensions.ServiceModel"/>
   5:        </bindingElementExtensions>
   6:      </extensions>
   7:      <behaviors>
   8:        <serviceBehaviors>
   9:          <behavior name="CustomerService">
  10:            <serviceDebug httpHelpPageUrl="http://localhost:55557/Provisioning/CustomerService"
  11:              includeExceptionDetailInFaults="true" />
  12:            <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:55556/Provisioning/CustomerService" />
  13:            <serviceTimeouts transactionTimeout="00:00:40" />
  14:          </behavior>
  15:        </serviceBehaviors>
  16:      </behaviors>
  17:      <bindings>
  18:        <customBinding>
  19:          <binding name="tcpCompressed" openTimeout="00:00:20" receiveTimeout="00:00:40"
  20:            sendTimeout="00:01:30">
  21:            <compression algorithm="BZip2" level="Normal"/>
  22:            <transactionFlow />
  23:            <binaryMessageEncoding maxReadPoolSize="32"
  24:                              maxWritePoolSize="32"
  25:                              maxSessionSize="4096">
  26:              <readerQuotas
  27:                  maxArrayLength="8000"
  28:                      maxBytesPerRead="4096"
  29:                      maxDepth="32"
  30:                      maxNameTableCharCount="16384"
  31:                      maxStringContentLength="65536" />
  32:            </binaryMessageEncoding>
  33:            <tcpTransport hostNameComparisonMode="WeakWildcard" transferMode="StreamedResponse"
  34:            maxReceivedMessageSize="1048576000">
  35:            </tcpTransport>
  36:          </binding>
  37:        </customBinding>
  38:      </bindings>
  39:      <services>
  40:        <service behaviorConfiguration="CustomerService" name="DE.CapeVision.Windows.Services.AgentService.Components.ProjectProvisioningWorkflow.CustomerService">
  41:          <endpoint address="net.tcp://localhost:20102/Provisioning/CustomerService"
  42:            binding="customBinding" bindingConfiguration="tcpCompressed"
  43:            contract="DE.CapeVision.Common.Contracts.Customers.ICustomerService" />
  44:        </service>
  45:      </services>
  46:    </system.serviceModel>

Es funktionierte mit der Konfiguration recht gut, allerdings kam irgendwann die Stelle, die ein weitersuchen erforderte, ich hatte keine Authentifizierung. Aber ich wollte unbedingt WindowsSecurity für die Anwendung haben. Es handelt sich um eine kleine Intranet-Anwendung. Authentifizierung ist ein wesentliches Merkmal zur minimalen Absicherung des Dienstes. Ein halber Tag und viele Kämpfe mit der MSDN Doku, habe ich es geschafft. Am Ende fehlten die beiden Elemente vor dem Transport (dick hervorgehoben 33-36), die Konfiguration sah so aus:

   1:    <system.serviceModel>
   2:      <extensions>
   3:        <bindingElementExtensions>
   4:          <add name="compression" type="WcfExtensions.ServiceModel.Configuration.CompressionElement, WcfExtensions.ServiceModel"/>
   5:        </bindingElementExtensions>
   6:      </extensions>
   7:      <behaviors>
   8:        <serviceBehaviors>
   9:          <behavior name="CustomerService">
  10:            <serviceDebug httpHelpPageUrl="http://localhost:55557/Provisioning/CustomerService"
  11:              includeExceptionDetailInFaults="true" />
  12:            <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:55556/Provisioning/CustomerService" />
  13:            <serviceTimeouts transactionTimeout="00:00:40" />
  14:          </behavior>
  15:        </serviceBehaviors>
  16:      </behaviors>
  17:      <bindings>
  18:        <customBinding>
  19:          <binding name="tcpCompressed" openTimeout="00:00:20" receiveTimeout="00:00:40"
  20:            sendTimeout="00:01:30">
  21:            <compression algorithm="BZip2" level="Normal"/>
  22:            <transactionFlow />
  23:            <binaryMessageEncoding maxReadPoolSize="32"
  24:                              maxWritePoolSize="32"
  25:                              maxSessionSize="4096">
  26:              <readerQuotas
  27:                  maxArrayLength="8000"
  28:                      maxBytesPerRead="4096"
  29:                      maxDepth="32"
  30:                      maxNameTableCharCount="16384"
  31:                      maxStringContentLength="65536" />
  32:            </binaryMessageEncoding>
  33:            <security authenticationMode="SspiNegotiatedOverTransport"
  34:                   requireSecurityContextCancellation="false">
  35:            </security>
  36:            <windowsStreamSecurity protectionLevel="EncryptAndSign"/>
  37:            <tcpTransport hostNameComparisonMode="WeakWildcard" transferMode="StreamedResponse"
  38:            maxReceivedMessageSize="1048576000">
  39:            </tcpTransport>
  40:          </binding>
  41:        </customBinding>
  42:      </bindings>
  43:      <services>
  44:        <service behaviorConfiguration="CustomerService" name="DE.CapeVision.Windows.Services.AgentService.Components.ProjectProvisioningWorkflow.CustomerService">
  45:          <endpoint address="net.tcp://localhost:20102/Provisioning/CustomerService"
  46:            binding="customBinding" bindingConfiguration="tcpCompressed"
  47:            contract="DE.CapeVision.Common.Contracts.Customers.ICustomerService" />
  48:        </service>
  49:      </services>
  50:    </system.serviceModel>

Die Clientseitige Konfiguration unterscheidet sich nur minimal von der gegebenen, es sollte sich schnell erstellen lassen. Hier der Vollständigkeit die Client-Seite:

   1:    <system.serviceModel>
   2:      <extensions>
   3:        <bindingElementExtensions>
   4:          <add name="compression" type="WcfExtensions.ServiceModel.Configuration.CompressionElement, WcfExtensions.ServiceModel"/>
   5:        </bindingElementExtensions>
   6:      </extensions>
   7:      <bindings>
   8:        <customBinding>
   9:          <binding name="tcpCompressed" openTimeout="00:00:20" receiveTimeout="00:00:40"
  10:            sendTimeout="00:01:30">
  11:            <compression algorithm="GZip2" level="Fast"/>
  12:            <transactionFlow />
  13:            <binaryMessageEncoding maxReadPoolSize="32"
  14:                              maxWritePoolSize="32"
  15:                              maxSessionSize="4096">
  16:              <readerQuotas
  17:                  maxArrayLength="8000"
  18:                      maxBytesPerRead="4096"
  19:                      maxDepth="32"
  20:                      maxNameTableCharCount="16384"
  21:                      maxStringContentLength="65536" />
  22:            </binaryMessageEncoding>
  23:            <security authenticationMode="SspiNegotiatedOverTransport"
  24:                   requireSecurityContextCancellation="false">
  25:            </security>
  26:            <windowsStreamSecurity protectionLevel="EncryptAndSign"/>
  27:            <tcpTransport hostNameComparisonMode="WeakWildcard" transferMode="StreamedResponse"
  28:            maxReceivedMessageSize="1048576000"/>
  29:          </binding>
  30:        </customBinding>
  31:      </bindings>
  32:      <client>
  33:        <endpoint address="net.tcp://localhost:20102/Provisioning/CustomerService" binding="customBinding" bindingConfiguration="tcpCompressed" contract="DE.CapeVision.Common.Contracts.Customers.ICustomerService" />
  34:      </client>
  35:    </system.serviceModel>

Hier natürlich noch der manipulierte Source Code der WCF-Extensions: Download. Um es produktiv einzusetzen muss allerdings noch etwas geschraubt werden, damit Performance Informationen abgegriffen werden können. Bis auf die 2 Trace-Ausgaben ist derzeit nichts enthalten.

UPDATE: Ich habe heute eine kleine Unschönheit gefixed, der Code in der Quelle ist entsprechen aktualisiert. Die Channels werden nicht sauber durch gereicht, so dass es unter Umständen zu einer Cast-Exception in der CompressionChannelBase kommt.

Technorati-Tags: ,,