Mehr von Jürgen Gutsch

Mehr von Jürgen Gutsch

Empfehlungen von Jürgen Gutsch

Blog-Empfehlungen von Jürgen Gutsch

Willkommen bei ASP.NET Zone. Anmelden | Registrieren | Hilfe

Jürgen Gutsch

ASP.NET und mehr...

News

Endspurt: ASP.NET MVC 2 RC 2 Released

Für alle die es noch nicht mitbekommen haben: Die RC 2 des ASP.NET MVC 2 ist raus.

Mehr zu RC 2 hat Phil Haack in diesem Beitrag: ASP.NET MVC 2 RC 2 Released

Download

DotNetKicks-DE Image
Neues und neue Termine für den .NET-Stammtisch Konstanz-Kreuzlingen

Es ist kaum zu glauben, aber es ist schon über ein Jahr vergangen seit Peter und ich den .NET-Stammtisch Konstanz-Kreuzlingen ins Leben gerufen haben.

In diesem Jahr ist Viel passiert: Wir hatten einige Prominente Sprecher da, wie z. B: Michael Schwarz, Albert Weinert, Thomas Schissler, Golo Roden, Gregor Biswanger und Stefan Lieser und wir natürlich selber als Sprecher die ersten Erfahrungen sammeln dürfen. Und mit jedem Treffen ist die Teilnehmerzahl etwas gewachsen.

Viele interessante und interessierte Leute bilden eine bunte Mischung innerhalb des Stammtisches und sorgen für abwechslungsreiche Diskussionen, auch abseits der .NET-Themen.

Leider kann Peter dem Stammtisch, aus beruflichen Gründen, nicht mehr als Group Leader zur Verfügung stehen, weshalb ich innerhalb des Stammtisches nach einer weiteren Unterstützung umschauen musste und zum Glück auch gefunden habe.
Neu im Team sind jetzt Tilo Schinke und Johannes Fritsch.
Ich freue mich sehr, dass sich die beiden bereiterklärt haben den Stammtisch zu unterstützen. Vielen Dank dafür :-)

Desweiteren freue ich mich sehr über die ersten Vorträge die von Mitgliedern des Stammtisches vorgeschlagen und auch gehalten werden.

Somit steht auch die Terminplanung für die nächsten sechs Monate:

  • 10.02.2010 – 12. Treffen
    Peter Bucher mit einer kurzen Einführung in die Entstehung von LightCore
    Jürgen Gutsch mit eine Live Coding Demo zu Dependency Injection mit LighCore
  • 10.03.2010 – 13. Treffen
    Golo Roden mit Visual Studio 2010 / .NET Framework 4.0 und C# 4.0 Neuerungen
  • 19.03.2010 – 14. Treffen (außerhalb der Reihe)
    Robert Meyer mit einem Open Space zu BizTalk Server 2009
  • 14.04.2010 – 15. Treffen
    Tilo Schinke mit Datenmodellierung – Relationales Mapping oder Objektpersistenz
  • 12.05.2010 – 16. Treffen
    Johannes Fritsch mit ASP.NET MVC mit NHibernate unter Mono
  • 09.06.2010 – 17. Treffen
    Jürgen Gutsch mit WebDAV - Die universelle Schnittstelle.

Natürlich Freue ich mich auf ein weiteres erfolgreiches und abwechslungsreiches Jahr mit dem .NET-Stammtisch Konstanz-Kreuzlingen und darauf weitere interessante Menschen kennenzulernen und auch den einen oder anderen prominenten Sprecher bei uns begrüßen zu dürfen.

Für die letzten zwölf Monate bedanke mich herzlich bei allen Teilnehmern und Mitgliedern, ohne die der Stammtisch sicherlich ein schnelles Ende gefunden hätte und natürlich bei allen Sponsoren die für die vielen Give Aways und den Unterhalt der Räumlichkeiten gesorgt haben.

DotNetKicks-DE Image
System.Runtime.InteropServices.COMException beim Laden eines ASP.NET Web Projektes

nachdem ich meinen Rechner neu aufgesetzt habe, erhielt ich beim Öffnen einer Solution mit einem ASP.NET Web Projekt eine “System.Runtime.InteropServices.COMException” und das Web Projekt wurde nicht geladen.

Nach längerem Suchen fand ich den Bug auch bei Microsoft: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=317124 und die Lösung bei Robert Boedigheimer in folgendem Beitrag: System.Runtime.InteropServices.COMException in WAP VS 2008 Project

Ich hatte ganz einfach vergessen die Metabase Kompatibilität mit zu installieren.

DotNetKicks-DE Image
DI / IoC mit LightCore

Was für Peter Bucher vor Monaten als Einstieg in TDD begonnen hatte, ist inzwischen ein Framework für Dependency Injection und Inversion of Control geworden.

Entstanden ist das kleine, feine uns super schnelle LightCore :-)

Ich selber nutze LightCore schon seit dem ersten Beta-Status in einem eigenem Projekt und bin bereits dabei LightCore in die Website des .NET-Stammtisch Konstanz-Kreuzlingen (http://dotnetkk.codeplex.com/) einzubinden.

Die Features von LightCore können hier angeschaut werden:
http://lightcore.peterbucher.ch/features.aspx

Der Download der aktuellen Version per SVN ist hier beschrieben:
http://lightcore.peterbucher.ch/download.aspx

DotNetKicks-DE Image
LINQ und LINQ to SQL

Neulich erhielt ich eine E-Mail mit einigen Fragen zur Verwendung von “LINQ to SQL” in n-Tier-Applikationen, die ich hier anonymisiert beantworten möchte:

Wie sieht Microsoft beim Einsatz von “LINQ to SQL” die Machbarkeit von n-Tier-Applikationen, die über eine separate Datenzugriffsschicht verfügen?

Da ich nicht Microsoft bin und auch kein offizielles Statement von Microsoft zu dieser Problematik kenne, kann ich diese Frage so nicht beantworten. Ich kann nur sagen, dass es Beispiel-Applikationen von Microsoft gibt, in denen durchaus “LINQ to SQL” innerhalb der Datenzugriffsschicht eingesetzt wird.

Wenn ich das richtig sehe, krankt “LINQ to SQL” bei seiner Nutzung mit .NET daran, dass ich bei der Nutzung aller automatisch generierten Objekte auf allen Ebenen der Anwendung einen Verweis auf “LINQ to SQL” benötige, oder?

Wenn man die automatisch generierten Objekte in der ganzen Applikation nutzen möchte, ist das sicher so. Aufgrund von der Austauschbarkeit der Datenzugriffsschicht würde ich allerdings empfehlen diese automatisch generierten Objekte nicht über alle Schichten hinweg zu verwenden, sondern “LINQ to SQL” komplett in der Datenzugriffsschicht zu kapseln.

Oder ich führe eine (aufwändig zu implementierende) Mapping-Schicht ein, in der ich die “LINQ to SQL”-generierten Datenklassen in anwendungsinterne Objekte übersetze.

Das wäre eine Möglichkeit, aber aus meiner Sicht nicht empfehlenswert. Ich würde bei einer klassischen 3-Schicht-Architektur eine vierte parallele vertikale Schicht einbinden, welche die Datenobjekte enthält die über alle Schichten hinweg zur Verfügung stehen sollen.

Die Datenzugriffsschicht ist dann verantwortlich für das bereitstellen der Daten und das Mappen der Daten in die Datenobjekte der vierten parallelen vertikalen Schicht.

Für den Fall, dass mal per “LINQ to XML” auf eine XML-Datenbasis zugegriffen werden soll, muss so nur die Datenzugriffsschicht ausgetauscht werden.

Auch wenn ich Benutzeroberfläche (Grids, etc.) an “LINQ to SQL”-Results binden möchte, habe ich das Problem, dass ich damit ja die Datenlogik in die GUI ziehe, und damit die eigentlich unterste mit der eigentlich obersten Schicht verbinde...?

Auch das ist ein Grund für die oben beschriebene parallele vertikale Anwendungsschicht. “LINQ to SQL” ist auf diese Art komplett von den anderen Schichten entkoppelt und die Datenzugriffsschicht liefert nur die gewünschten Objekte.

DotNetKicks-DE Image
Microsoft SharePoint 2007 Video-Training

Vor einiger Zeit hat Gregor Biswanger sein erstes Video für video2brain veröffentlicht. Da ich mich ebenfalls sehr für den SharePoint 2007 interessiere habe ich die Gelegenheit bekommen in das Video-Training rein schauen zu dürfen.

Bei dem Video-Training handelt es sich um 8 Stunden Training mit 78 Lektionen über die Installation, Administration und Einrichtung von Microsoft SharePoint 2007. Außerdem zeigt Gregor wie Sharepoint mit Office 2007 zusammenarbeitet und wie man selber für Sharepoint entwickelt.

Wer jetzt allerdings den Gregor gekämmt und in Anzug und Krawatte erwartet hat Pech gehabt. Gregor begrüßt einen hier im gewohnten lockeren Stil; Gregor wie er leibt und lebt:

Das tolle an diesem Video-Training ist der “Mach Mit!-Modus” bei dem sich das Video verkleinert in der linken oberen Ecke des Bildschirms, immer im Vordergrund, platziert. So kann man die einzelnen Schritte zusammen mit Gregor ausprobieren.

Wer möchte kann sich unter folgendem Link ein paar Probevideos anschauen: http://www.video2brain.com/de/products-419-2.htm

Das Video-Training ist für alle Einsteiger, Interessierte und Wiedereinsteiger (wie mich) absolut geeignet. Aber auch erfahrenere SharePoint Administratoren und Entwickler finden sicher deren einen oder anderen Tipp. Ich finde Gregor hat hier seinen Job absolut sauber gemacht *daumenhoch*, denn er präsentiert hier den Microsoft SharePoint 2007 in einfachen, kleinen und verständlichen schritten.

Mich hat es schon in den ersten Lektionen in den Fingern gekitzelt. Ich wurde praktisch gezwungen in den “Mach Mit!-Modus” zu wechseln und parallel alles auszuprobieren :-)

DotNetKicks-DE Image
Scott Hanselman’s Baby Smash!

baby smash!

Vor einiger Zeit bin ich auf ein Webcast von Scott Hanselman gestoßen in dem er eine ClickOnce Anwendung vorstellte. Seine Beispielanwendung war ein kleines Programm namens Baby Smash!

Das Programm

Baby Smash! ist, wie der Name schon sagt, ein Computerspiel für kleine Kinder. Ich fand das Programm auf Anhieb interessant und installierte es Zuhause auf meinem Rechner.

Baby Smash! ist eine WPF-Anwendung die per Click Once installiert werden kann. Das Spiel sperrt den Bildschirm und erzeugt per Fullscreen eine weiße Fläche. Werden nun beliebige Tasten gedrückt erscheinen Buchstaben und Symbole auf dem Bildschirm. Die Buchstaben auf der Tastatur erzeugen bunte Buchstaben, Sonderzeichen und andere Tasten erzeugen zufällige Symbole (wie Sterne, Fünfecke, Herzen, etc.). Jedes Mal wenn ein Symbol oder Buchstabe erscheint wird auch ein kinderlachen ausgegeben. Buchstaben werden wahlweise Vogelesen oder es wird ebenfalls ein kinderlachen ausgegeben.

Selbst die Maus ist mit Funktionen belegt: Klickt man irgendwo auf dem Bildschirm, wird ein bunter Punkt erzeugt. Fährt man mit gedrückter Maustaste über den Schirm, wird eine Mausspur mit bunten Punkten erzeugt und eine passende Melodie ausgegeben. Beim drehen des Scroll-Rades, wird je nach Drehrichtung, ein Geräusch eines erstaunten oder eines wissenden Kindes ausgegeben. (“Hääääääää?” und “Ahhhhhhhhh”) Die Symbole und Punkte verschwinden nach einer gewählten Zeit oder wenn eine bestimmte Anzahl überschritten ist.

Außerdem werden fast alle Tastenkürzel gesperrt, so das die Kinder beim spielen nichts kaputt machen können. [Alt][F4] zum beenden des Spiels und [Strg][Shift][Alt]Time für die Spiele Optionen stehen noch zur Verfügung.

Die Zielgruppe

Mich interessierte natürlich hauptsächlich auch wie Hendrik auf das Spiel reagieren würde.

Sobald er also in der Lage war, an meinem Bauch gelehnt auf meinem Schoß zu sitzen. Setzte ich mich mit ihm vor den Rechner und startete das Spiel. Es dauerte nicht lang, bis er - “ganz wie der Papa” - wild auf der Tastatur herum hauen wollte.

Das Ergebnis war besser als erwartet. Hendrik verstand sehr schnell, dass sein wildes Gehaue eine Reaktion auf dem Bildschirm auslöste. Er haute auf die Tastatur und beobachtete anschließend fasziniert den Bildschirm und lauschte den Geräuschen. Sobald keine Töne und keine neuen bunten Symbole mehr zu sehen waren, fing er wieder an mit Begeisterung auf der Tastatur herum zuhauen.

Das Fazit

Scott Hanselmann hat ein Spiel geschaffen, dass sogar Babys faszinieren und begeistern kann.

Nein, mein Sohn wird nicht zu einem Zocker erzogen. Zumindest hoffe ich das. Er wird das Spiel nur einige Minuten pro Woche oder Monat zu Gesicht bekommen. Aber es ist faszinierend, wie er mit jeder Altersstufe die er erreicht immer wieder etwas anders auf das Spiel reagiert

Infos

Infos und Download: http://www.hanselman.com/babysmash/

DotNetKicks-DE Image
www.asp-net-mvc.com

Soeben bin ich auf Sean McAlinden's Blog gestoßen und zwar auf eine Beitrag, in dem Sean eine kleine Helferklasse beschreibt, mit der man relativ einfach an eingebettete Ressourcen kommen kann: ASP.Net MVC Embedded Resource Helper Class

Ganz unten unter Beitrag fand ich einen Link auf www.asp-net-mvc.com. Und da ich generell auf alles drauf klicke was irgendwie für ich interessant sein könnte. Fand ich eine Seite vor die sowohl von Sean McAlinden als auch von Paul Thorrington. Was zuerst aussieht wie eine kommerzielle Website entpuppte sich als Präsentation kleiner und feiner ASP.NET MVC Helfer. Insgesamt gibt es sieben kleine Helfer zum anschauen, herunterladen und nutzen.

http://www.asp-net-mvc.com/MvcHelpers

DotNetKicks-DE Image
Stirnrunzeln über “Wie viel Sinn machen Unittests?”

Seit Oktober 2009 verfolge ich mit Begeisterung das Streitgespräch zwischen Golo Roden und Peter Bucher. Beide Autoren stellen sich jeden Monat von neuem diversen Fragen und Problemen aus dem Bereich der Softwareentwicklung.

Auch dieses mal kann man wieder über ein Spannendes Thema lesen: Wie viel Sinn machen Unittests?

Diesmal allerdings fühle ich mich gezwungen selber ein Kommentar über den neuesten Beitrag zu schreiben. Denn das erste mal seit dieser Serie bin ich sehr erstaunt, bzw. sogar leicht erschreckt, über Golos Beitrag.

So schreibt Golo, dass Unit Tests zwar wünschenswert sind und und durchaus Sinn machen, allerdings nur an explizit ausgewällten Stellen:

Golo schrieb:
Wie viel Sinn machen Unittests also nun? Zusammengefasst kann man sagen, dass Unittests – an der richtigen Stelle eingesetzt – durchaus Sinn ergeben, dass diese Stellen aber explizit ausgewählt werden sollten.

Des weiteren schreibt er, dass eine 100%ige Testabdeckung zwar wünschenswert ist, aber in der Praxis kaum möglich ist und sogar auf kosten der OOP geht.

Als Begründung nennt er drei Aspekte, auf die ich hier etwas eingehen möchte:

Golo schrieb:
Der bestehende objektorientierte Aufbau ist unter OOP- und stilistischen Aspekten sauber umgesetzt, läuft einer guten Testbarkeit allerdings zuwider.

Diesen ersten Aspekt kann ich leider nicht nachvollziehen, bzw. halte ihn aus meiner Erfahrung heraus sogar für paradox. Im Gegenteil bin ich der Meinung, dass eine saubere, allen Regeln des OOP entsprechende Architektur testbarer ist. Ich gehe sogar noch weiter und behaupte, dass eine mir TDD umgesetzte Anwendung OOP besser umsetzen kann als eine, nicht mit Unit Tests abgedeckte Anwendung.

Denkt man darüber nach was Unit Tests eigentlich sind, nämlich Tests der kleinsten vorhandenen Units, beeinträchtig das keineswegs negativ den aufbau der Anwendung nach allen regeln der OOP. Ein Unit Test testet die kleineste ansprechbare Einheit einer Klasse, das ist eine Methode oder eine Eigenschaft, aber weder deren Abhängigkeiten, noch komplexe Routinen und Szenarien.

Unit Tests unterbinden Abhängigkeiten:

Golo schrieb:
Es bestehen zahlreiche Abhängigkeiten zu externen Komponenten, die sich nicht oder nur mit sehr viel Aufwand simulieren lassen.

Eine saubere Architektur besteht ohne Abhängigkeiten. Mit Hilfe von IoC Containern und Dependency Injection werden Abhängigkeiten gelöst. Dadurch lassen sich die einzelnen Units noch einfacher Testen. Dadurch lassen sich z. B. ohne Aufwand andere spezielle für diese Tests benötigte Bibliotheken laden. Das wiederspricht also schon dem zweiten Aspekt. Beispielswiese lässt sich für den Unit Test eine Library laden, die den Zugriff auf eine Im-Memory-Datenbank ermöglicht, statt auf einen SQL Server Datenbank.

Eine weitere Möglichkeit sich in in Unit Tests von Abhängigkeiten zu lösen sind Mocking Frameworks wie z. B: RhinoMocks:

Golo schrieb:
Es bestehen Abhängigkeiten zur konkreten Laufzeitumgebung, die sich nicht oder nur mit sehr viel Aufwand nachbilden lassen.

Mocking Frameworks werden genutzt um z. B. abhängige Klassen zu simulieren. Anhand eines Interfaces werden “gefälschte” Objekte erzeigt, die lediglich die benötigten Funktionen bereitstellen und die gewünschten werte liefern.

Datenzugriffsklassen, Dateienzugriffsklassen, eigentlich alle Abhängigkeiten lassen sich in einer sauberen Umgebung simulieren und der Unit Test konzentriert sich einzig und allein auf das Unit, statt Abhängigkeiten berücksichtigen zu müssen.

Golo schrieb:
Um Webbrowser-spezifisches Verhalten zu simulieren, müssten die Eigenheiten des jeweiligen Webbrowsers im Unittest nachgebildet werden. Alternativ könnten der entsprechenden gewünschte Webbrowser automatisiert werden – was seinerseits allerdings einen ziemlichen Aufwand nach sich zieht.

Das ist meiner Meinung nach die Aufgabe eines integrationstests, nicht die eines Unit Tests. Da hier ein komplettverhalten getestet wird und nicht das Verhalten einer einzelnen Unit. Um diese Unit zu testen muss der HttpRequest der von der Unit benötigt wird, simuliert werden.

Golo schrieb:
Ebenfalls problematisch ist multithreaded Code, sofern bestimmte Konstellationen in den einzelnen Threads getestet werden sollen – da das Umschalten zwischen den Threads vom aktuellen Kontext des Prozessors beziehungsweise des Betriebssystems abhängt, kann sich das Verhalten von Ausführung zu Ausführung unterscheiden.

Auch hier sollte der Unit Test nicht den Thread testen , sondern die Units die innerhalb der Threads arbeiten, alles andere wäre kein Unit Test.

Mein Fazit:

Die Benutzung von Unit Tests von möglichen Abhängigkeiten “abhängig zu machen” ist in Zeiten mit IOC Containern und Mocking Frameworks nicht mehr haltbar. Mit Hilfe von diesen Hilfsmitteln ist garantiert eine Testabdeckung von annähernd 100% machbar.

Update:

Hier noch ein Statement zum Thema von Thomas Bandt.

Lesenswert sind auch die Kommentare zu Golos Beitrag unter anderem auch von Ralf Westphal.

Mein Fazit (das zweite):

Wie Thomas kann ich bestätigen dass TDD am Anfang sehr, sehr schwierig ist. Wenn man Jahrelang einfach drauf los entwickelt hat, ist es ein wahrer Kraftakt und es erfordert eine menge Konzentration uns Selbstdisziplin Testgetrieben zu entwickeln.

DotNetKicks-DE Image
Zweiter Start mit NHibernate

Es ist eine ganze Weile her seit ich mir das letzte Mal NHibernate angeschaut habe. Damals hielt ich NHibernate für zu unflexibel und zu kompliziert, bzw. aufwändig in der Konfiguration. Zumindest damals musste das Mapping der Datenbank auf die einzelnen Objekte in XML-Dateien geschrieben werden. Anschließend wurde per externes Programm, aus den Mapping Klassen generiert, die dann für den Zugriff auf die Datenbank genutzt werden konnten. Gerade die Nutzung eines externen Tools zur Generierung der nötigen Klassen erschien mir sehr umständlich.

Vor ein paar Wochen war es wieder so weit, dass ich mir NHibernate angeschaut habe.

Der Grund waren ein paar positive Äußerungen in der .NET Community. Dort war immer wieder zu lesen, wie gut NHibernate im Zusammenhang mit Fluent NHibernate und LINQ to NHibernate sei. Alleine schon die Aussicht auf LINQ und de Konfiguration über Fluent Interfaces machten mich wieder neugierig auf den am häufigsten erwähnten OR-Mapper.

Enttäuscht wurde ich nicht, ganz im Gegenteil. Mit dem Fluent NHibernate und LINQ to NHibernate ist es eine Freude mit NHibernate zu arbeiten. Nicht nur dass man ganz ohne XML-Konfigurationen auskommt, mit Hilfe des Fluent NHibernate lässt sich das Mapping und die Konfiguration per .NET Code schreiben. Also ob das nicht genug wäre, lässt sich mit Fluent NHibernate sogar die Datenbank dann aus dem erstellten Mapping und der Konfiguration generieren.

Hier mal das Ergebnis meiner ersten Spielerei.

Benötigt werden Fluent NHibernate (welches unter folgender URL heruntergeladen werden kann: http://fluentnhibernate.org/, die NHibernate.dll ist dort bereits enthalten) und LINQ to NHibernate (http://sourceforge.net/projects/nhibernate/files/

Vorbereitung

Angefangen hab ich mit der Erstellung meiner Daten-Objekte

Person.cs

public class Person: Entity<Person>
{
  protected override void Initialize()
  {
    Projects = new List<Project>();
    Tasks = new List<Task>();
  } 
  public virtual List<Project> Projects { get; set; }
  public virtual List<Task> Tasks { get; set; }
  public virtual string FirstName { get; set; }
  public virtual string LastName { get; set; }
  public virtual string Email { get; set; }
  public virtual string Telefone { get; set; }
}

Projekt.cs

public class Project: Entity<Project>
{
  protected override void Initialize()
  {
    Persons = new List<Person>();
    Tasks = new List<Task>();
  } 
  public virtual List<Person> Persons { get; set; }
  public virtual List<Task> Tasks { get; set; }
  public virtual string Name { get; set; }
  public virtual string Description { get; set; }
  public virtual DateTime StartDate { get; set; }
  public virtual DateTime EndDate { get; set; }
}

Task.cs

public class Task: Entity<Task>
{
  public virtual Person Person { get; set; }
  public virtual Project Project { get; set; }
  public virtual string Name { get; set; }
  public virtual string Description { get; set; }
  public virtual DateTime StartDate { get; set; }
  public virtual DateTime EndDate { get; set; }
}

Wie man jetzt evtl. erkennen kann ist eine kleine, einfache Aufgabenverwaltung geplant. Alle drei Objekte erben von einer generischen Basisklasse die weitere Funktionen und die Eigenschaft Id, vom Typ Guid – die in jeder Klasse enthalten ist – bereitstellt.

Mapping

Jetzt wird es dann eigentlich erst interessant: per Fluent NHibernate müssen die Mappings erzeugt werden. Als erste für die Person-Klasse:

public class PersonClassMap: ClassMap<Person>
{
  public PersonClassMap()
  {
    Table("Persons");
    Id(d => d.Id).GeneratedBy.Guid();
    Map(d => d.FirstName).Not.Nullable().Length(50);
    Map(d => d.LastName).Not.Nullable().Length(50);
    Map(d => d.Email).Not.Nullable().Length(50);
    Map(d => d.Telefone).Not.Nullable().Length(50);
    HasMany(d => d.Tasks)
      .Cascade.All()
      .KeyColumn("PersonId")
      .Inverse();
    HasManyToMany(d => d.Projects)
      .Cascade.All()
      .Table("Person2Project")
      .ParentKeyColumn("PersonId")
      .ChildKeyColumn("ProjectId");
  }
}

Als erste wird hier der Name der Datenbank-Tabelle definiert. Anschließend mit der Methode Id() der Primärschlüssel. GeneratedBy.Guid() gibt an dass es sich um einen Autogenerierten Guid-Wert handeln soll.

Die Methode Map ist die einfachste, sie mappt lediglich die Eigenschaften auf die Felder in der Datenbank. Not.Nullable()und Length(50) sind sprechend.

Interessant wird es mit HasMany(), hier wird definiert, dass einer Person mehrere Aufgaben zugewiesen sein können. KeyColumn("PersonId") zeigt auf den Fremdschlüssel in der Tabelle „Tasks“. Inverse zeig an dass es das Gegenstück zur Referenzierung in der Klasse Task ist. Dort sieht die Referenz wie folgt aus:

References(r => r.Person, "PersonId");

Die Angabe des Spaltennamens (2. Parameter) ist notwendig wenn man diesen nicht autogeneriert haben möchte, einem bestimmten Namensschema in der Datenbank folgen möchte oder bereits einen Namen in der Datenbank vergeben hat Kniffliger als HasMany() ist HasManyToMany() hier wird eine n:m Beziehung dargestellt und definiert, dass mehrere Personen mehreren Projekten zugeordnet werden können. Wenn der Tabellenname nicht autogeneriert werden soll muss dieser angegeben werden, genauso wie die Spalten. Erscheint zunächst einfach, allerdings muss man beachten, dass das Gegenstück (im Mapping für die Projekte) rückwärts verweist:

HasManyToMany(d => d.Persons)
  .Cascade.All()
  .Table("Person2Project")
  .ParentKeyColumn("ProjectId")
  .ChildKeyColumn("PersonId")
  .Inverse();

Man sieht, die Spaltennamen für ParentKeyColumn sind vertauscht und es muss wieder ein Inverse() angehängt sein.

Die anderen beiden Mappings sehen wie folgt aus:

public class ProjectClassMap: ClassMap<Project>
{
  public ProjectClassMap()
  {
    Table("Projects");
    Id(d => d.Id).GeneratedBy.Guid();
    Map(d => d.Name).Not.Nullable().Length(50);
    Map(d => d.Description).Not.Nullable().Length(4000);
    Map(d => d.EndDate).Not.Nullable();
    Map(d => d.StartDate).Not.Nullable();
    HasManyToMany(d => d.Persons)
      .Cascade.All()
      .Table("Person2Project")
      .ParentKeyColumn("ProjectId")
      .ChildKeyColumn("PersonId")
      .Inverse();
    HasMany(d => d.Tasks).Cascade.All().KeyColumn("ProjectId").Inverse();
  }
}

public class TaskClassMap: ClassMap<Task>
{
  public TaskClassMap()
  {
    Table("Tasks");
    Id(d => d.Id).GeneratedBy.Guid();
    Map(d => d.Name).Not.Nullable().Length(50);
    Map(d => d.Description).Not.Nullable().Length(4000);
    Map(d => d.EndDate).Not.Nullable();
    Map(d => d.StartDate).Not.Nullable();
    References(r => r.Project, "ProjectId");
    References(r => r.Person, "PersonId");
  }
}

Konfiguration

Im nächsten Schritt muss die Verbindung zur Datenbank konfiguriert werden und bei Bedarf eine SessionFactory erzeugt werden. Dazu habe ich mit eine statische Klasse angelegt die wiederum zwei Methode enthält: Die erste Methode erstellt die Konfiguration und die Zweite Methode erstellt die SessionFactory anhand dieser Konfiguration.

public static FluentConfiguration CreateConfiguration()
{
  return Fluently.Configure()
    .Database(MsSqlConfiguration.MsSql2005
      .ConnectionString(c => c.FromAppSetting("DbConnection"))
      .ShowSql())
    .Mappings(m => m.FluentMappings
      .AddFromAssemblyOf<IEntity>());
}

Im ersten Teil der Fluently Configuration wird die Verbindung zur Datenbank definiert. Hierfür gibt es verschiedenste Möglichkeiten. (Mehr Möglichkeiten lassen sich aus der Dokumentation entnehmen: http://wiki.fluentnhibernate.org/Main_Page) Ich habe MS SQL 2005 als Datenbankserver gewählt und lese den ConnectionString aus den App.Settings, bzw. der Web.Config aus. Außerdem möchte ich bei Fehlern den SQL-String sehen: ShowSql()

Anschließend wird das Mapping zugewiesen. Das geschieht ganz einfach indem man dem Fluent NHibernate sagt, wo die Assembly mit den Mappings liegen. Es werden automatisch alle Klassen als Mapping erkannt die von ClassMap<T> erben.

public static ISessionFactory CreateSessionFactory()
{
  return CreateConfiguration().BuildSessionFactory();
}

Die zweite Methode ruft die erste auf und erstellt eine neue SessionFactory. Ich habe die Configuration von der Erstellung der Session getrennt um für die Generierung der Datenbank einen Konfigurationspunkt – für die Generierung der Datenbank – dazwischen zuhängen, die ich für die einfache Erzeugung der SessionFactory nicht benötige.

public void SetupDatabase()
{
  FluentConfiguration conf = NHConfiguration.CreateConfiguration();
  conf.ExposeConfiguration(BuildSchema).BuildSessionFactory();
}
private static void BuildSchema(Configuration conf)
{
  new SchemaExport(conf).Drop(false, true);
  new SchemaExport(conf).Create(false, true);
}

Mit der Methode ExposeConfiguration() werden Anweisungen zum Exportieren des Datenbankschemas eingebunden. Das Schema wird in dem Fall in die Datenbank selber exportiert. Es wird also die Datenbank erstellt.

Es empfiehlt sich die SessionFactory global, anwendungsweit bereit  zu halten, da die Erzeugung der Factory sonst recht unperformant ist. Schließlich muss das Schema erst anhand des erstellten Mappings generiert werden

private static ISessionFactory sessionFactory;
public static ISessionFactory SessionFactory
{
  get
  {
    if (sessionFactory == null)
      sessionFactory = NHConfiguration.CreateSessionFactory();
    return sessionFactory;
  }
}

LINQ to NHibernate

Eine Session kann dann innerhalb eines Using-Blocks geöffnet werden:

using(var session = sessionFactory.OpenSession())
{
}

Innerhalb des Blocks kann dann endlich auch LINQ to NHibernate zum Einsatz kommen:

var q = from a in session.Linq<Person>()
        where a.FirstName != ""
        select a;

Die generische Methode Linq<T>() liefert ein Ergebnis vom Typ INHibernateQueryable<T> das wiederum von IQueryable<T> und IEnumerable<T> und somit wiederum bequem per LINQ abgefragt werden kann.

Fazit

NHibernate ist dadurch natürlich recht schnell einsetzbar, bequemer und auch etwas flexibler, denn das Mapping und auch die Konfiguration lassen sich theoretisch so natürlich auch dynamisch erzeugen. Die Benutzung von LINQ erleichtert die Abfragen ungemein. Fluent NHibernate macht die Konfiguration und das Mapping lesbarer.

Ich denke mit den beiden oben vorgestellten Erweiterungen ist NHibernate wirklich eines der genialsten OR-Mapper.

Update:
Das Beispielprojekt gibt es hier zum herunterladen: NHibernateTestApplication.zip (2.4MB)

DotNetKicks-DE Image
jQuery Visual Cheat Sheet

Von Antonio Lupetti gibt es ein recht ausführliches jQuery Cheat Sheet zum kostenlosen Download. Das Cheaat Sheet enthält eine Übersicht über die wichtigsten jQuery Funktionen, sowie jQuery Selektoren und einige Beispiele zur Anwendung der Funktionen:

http://woork.blogspot.com/2009/09/jquery-visual-cheat-sheet.html

DotNetKicks-DE Image
VSTS beim .NET-Stammtisch Konstanz-Kreuzlingen

Etwas verspätet liefere ich hier noch einen kurzer Rückblick auf das sechste Treffen des .NET-Stammtisch Konstanz-Kreuzlingen.

Wie immer bin ich um 18:30Uhr im Raum F023 in der FH-Konstanz angekommen um die Session vorzubereiten. Strom und Beamer zu prüfen und die Videokamera aufzustellen. Diesmal war ich nicht der erste, denn Thomas stand schon drin und richtete den Laptop für seine Präsentation.

Thomas zeigte viele Neuerungen in den VSTS 2010 auch anhand einiger live Demos.

Als beeindrucktesten Neuerungen empfand ich die hierarchischen Workitems, sowie die viel Bessere Unterstützung der Tester unter anderem auch mit dem neuen Workitem-Typ “Testcase”, den Testaufzeichnungen und dem Videomitschnitt während des Testens. Der Entwickler kann so fehlgeschlagenen Tests nachvollziehen und muss unter Umständen nicht lange nach dem Fehler suchen. Auch für die Architekten wurden einige Neuerungen hinzugefügt.

Insgesamt werde ich wohl jedem empfehlen VSTS 2010 einzusetzen, bzw. auf die neue Version updaten, sobald sie Verfügbar ist.

Das Video und die Bilder zum Vortrag werde ich in den nächsten Wochen auf der Website des .NET-Stammtisch veröffentlichen.

Anschließend gingen wir alle in das Brauhaus wo wir in gemütlicher Atmosphäre, bei Frischgebrautem, weiter zum Thema Diskutieren konnten.

Danke nochmal an Thomas, dass er extra wegen uns aus Erlangen, zu uns nach Konstanz runter geheizt ist. :-)

DotNetKicks-DE Image
Grenzfälle – Wann ist Code Clean?

Aus meinem letzten Blogpost entwickelte sich eine interessante Diskussion zum Thema Clean Code.

Im Grunde ging es in dem Blogpost darum, dass ich mich beschwerte, dass es in LINQ to XML keine “saubere” Möglichkeit gibt XElements mit Namespaces abzufragen. Außer  mit einer vom Peter zur Verfügung gestellten Extension Method.

René wies mich per Kommentar darauf hin, dass man auch die statische Methode XName.Get() verwenden könne um Namen für XElemente mit Namespaces zu generieren.

Ich übernahm Renés Idee wie folgt:
XDocument xdoc = XDocument.Load(xmlResponseReader); 
XName xname = XName.Get("multistatus", "DAV:");
XElement xelement = xdoc.Element(xname);

Damit ging die ganze Diskussion los :-)

René war nun der Ansicht, dass diese drei Zeilen nicht Clean Code seien, da die Erzeugung einer separaten Variablen, die den Wert aus der statischen Methode zugewiesen bekommt, unnötig sei.

René schrieb:
In Bezug auf statische Methode bleibe ich aber bei der Aussage, dass wenn ich den Wert nur 1 mal benötige, dann rufe ich die Methode direkt auf, andernfalls nutze ich einen zusätzlichen Parameter.

René hat absolut recht, was die gezeigten Codes angeht. Die sind klein genug :-)

René und ich haben allerdings nun die unterschiedlichen Anforderungen nicht Berücksichtigt. Der im Blogpost dargestellte Code war natürlich vereinfacht, um das Prinzip zu veranschaulichen. In Wirklichkeit habe ich ein relativ großes XML mit verschiedensten Elementen deren Werte ich abfragen möchte.

Um jetzt mehrere XElemente abzufragen, sähe der Code nach Renés variante so aus:
string nsDAV = “DAV:”;
Folder inboxFolder = new Folder();
inboxFolder.HRef = xfolder.Element(XName.Get(“href”, nsDAV)).Value;
inboxFolder.DisplayName= xfolder.Element(XName.Get(“displayname”, nsDAV)).Value;
inboxFolder.FolderSize= xfolder.Element(XName.Get(“foldersize”, nsDAV)).Value;
inboxFolder.HasChildren= xfolder.Element(XName.Get(“haschildren”, nsDAV)).Value;
inboxFolder.HasSubs= xfolder.Element(XName.Get(“hassubs”, nsDAV)).Value;
// …

Eine Variable vom Typ XName zu erstellen macht hier natürlich keinen Sinn

Aus meiner Sicht bläht diese statische Methode den Code allerdings mehr auf, als die gezeigten Extension Methods:
XNamespace nsDAV = "DAV:";
Folder inboxFolder = new Folder();
inboxFolder.HRef = xfolder.Element(nsDAV, “href”).Value;
inboxFolder.DisplayName= xfolder.Element(nsDAV, “displayname”).Value;
inboxFolder.FolderSize= xfolder.Element(nsDAV, “foldersize”).Value;
inboxFolder.HasChildren= xfolder.Element(nsDAV, “haschildren”).Value;
inboxFolder.HasSubs= xfolder.Element(nsDAV, “hassubs”).Value;
// …

Zurück zum Clean Code: René war der Meinung das es kein Clean Code sei, wenn ich eine separate Variablenzuweisung schreibe. Ich dagegen bin der Meinung, dass man lieber zwei Zeilen schreiben sollte, als zu viele Anweisungen in eine Zeile zu setzen. Ich bin der Meinung das Der Code für jeden vor allem einfach lesbar sein sollte. Je mehr Anweisungen in einer Zeile zu finden sind, desto länger verharrt der “Leser” in der Zeile und desto schwieriger ist es die Zeile schnell zu verstehen. (Und mir ist es dabei egal, ob der Leser ein Einsteiger oder ein erfahrener Entwickler ist)

Natürlich kann es auch hier Ausnahmen geben. In dem letzten Code (oben) habe ich die Ermittlung des XElements und das Auslesen dessen Wertes in eine Zeile gesetzt. Hier wird allerdings auch der Lesefluss nicht beeinträchtigt:
XElement ermitteln => seinen Wert auslesen

An der Stelle habe ich natürlich die extremen Ansicht von Robert C. Martin übernommen, der in seinem Buch Clean Code schreibt, man solle den Code wie einen Zeitungsartikel lesen können. Das setzt nicht nur Lesbarkeit voraus, sondern auch die Einhaltung eines Lesefluss.

Nebenbei: ReSharper beeinflusst: Habe gerade versucht im Live Writer einen Schreibfehler mit [Alt][Enter] zu korrigieren *fg*

René schrieb:
Mein Verständnis von "Clean Code" fängt da an, wo der Code optimiert ist, funktionell korrekt und verständlich. Wenn ich nur den Schwerpunkt auf Verständlichkeit lege, dann hat das wenig mit "Clean Code" im eigentlichen Sinne zu tun.

Clean Code entsteht nur aus einem längeren Prozess heraus und kann nicht einfach so erzeugt, bzw. geschrieben werden. Clean Code entsteht unter anderem durch die Einhaltung der Prinzipien und Regeln des CCD. Clean Code entsteht dabei vor allem aus Wiederholungen von Reviews und Refactoring. Natürlich muss die Funktionalität des Codes immer im Vordergrund stehen, aber beim nachträglichen Bearbeiten seines Codes sollte nach und nach auch an der Lesbarkeit des Codes gearbeitet werden.

Pfadfinderregel:
Verlasse einen Ort sauberer, als du ihn vorgefunden hast.

Zu Ralfs Uommentar:

Jetzt ich gehe mal schnell auf den Kommentar von Ralf Westphal ein:

Ralf schrieb:
Ob
XDocument xdoc = XDocument.Load(xmlResponseReader);
XElement xelement = xdoc.Element("{DAV:}multistatus");

wirklich viel umständlicher ist
XDocument xdoc = XDocument.Load(xmlResponseReader);
XNamespace ns = "DAV:";
XElement xelement = xdoc.Element(ns, "multistatus");

wage ich eigentlich nicht zu beurteilen.

Stichwort: Redundanzen ;-)
Der Namespace “DAV:” kann öfter vorkommen. Ihn jedes Mal angeben zu müssen ist mühsam. Zudem lenkt der Namespace vom eigentlichen Elementnamen ab. Zumindest ist das die Erfahrung beim schreiben des Codes. Wenn man allerdings nur diese kleinen Codesnippets für sich betrachtet ist es wirklich egal.

Ralf schrieb:
Mir schiene jedoch eine Ext Meth, der ich keinen Namespace übergeben muss, noch geeigneter:
XDocument xdoc = XDocument.Load(xmlResponseReader);
XElement xelement = xdoc.Element("DAV:", "multistatus");

Bei so einer Extension Methode sehe ich keine Probleme. Allerdings arbeite ich in der Regel ungerne mit Strings, wenn es sich vermeiden lässt. Wenn es ein Objekt gibt versuche ich dieses zu nutzen.

Ralf schrieb:
An CCD wurde die Frage gestellt, ob 1 Statement pro Zeile angezeigt sei.

Meine Meinung dazu: da ist unter dem Radar von CCD

Logisch, das ist ja auch nicht Aufgabe des CCD das zu definieren. Wie oben bereits geschrieben gibt an dieser Stelle Robert C. Martin eine Empfehlung wie der Code seiner Ansicht nach am besten auszusehen hat. CCD verweist ja lediglich auf sein Buch.

Ralf schrieb:
Was der eine oder andere für lesbar hält, fällt in die Nähe eines Geschmacksurteils…

Im Detail, ja.

Ralf schrieb:
Das Gesamtbild muss stimmen. Und das kann im Detail dann auch mal unterschiedlich aussehen

Logisch.

Ralf schrieb:
Ich wäre zwar nicht allzu traurig, wenn C# nicht mehr als eine Anweisung pro Zeile zuließe, doch ich nehme gern auch die Möglichkeit mit, dass es mehrere sein dürfen.

Dem kann ich nur zustimmen…

Ralf schrieb:
Noch ein Wort zu statischen Methoden, die in der Diskussion auftauchten. Wenn die im API drinstecken, dann kann man nix machen. Sollten wir selbst aber statische Methoden schreiben? Eher nicht. (Auch wenn R# immer mal wieder vorschlägt, eine Methode statisch zu machen.) Der Grund: static methods don´t compose.

Da statische Methoden keine Interfacemethoden implementieren können, kann man ihre Funktionalität nicht gut injizieren. (Von Funktionszeigern darauf sehe ich mal ab.)

Dito…

Zeilenlänte und Schachtelungstiefe

Und damit damit folgende Aussage – die nicht ganz zum Ursprünglichen Thema passt - nicht in den Untiefen der Kommentarfunktion verloren geht, nehme ich sie ebenfalls hier mit rein.

Ralf schrieb:
Wichtiger finde ich zwei andere Dimensionen:

-Zeilenlänge

-Schachtelungstiefe

Eine Zeile mit wievielen Anweisungen auch immer sollte nicht über eine normale Editorfensterbreite hinausgehen. Wenn man scrollen muss, dann sinkt die Verständlichkeit bzw. die Aufnahmegeschwindigkeit rapide.

Und ich finde Schachtelungen beobachtenswert. Es ist ein Unterschied, ob ich

A(B(C()));

oder

var c=C();

var b=B(c);

A(b);

schreibe. Letzteres macht mehr Aufwand, ist aber flüssiger zu lesen, weil man von oben nach unten lesen kann.

Bei der Schachtelung kehrt sich die Leserichtung quasi um: man muss von innen nach außen, d.h. eher von rechts nach links lesen. Das hakt schnell mal. Da hilft auch eine andere Schreibweise nicht viel wie

A(

B(

   C()

  )

);

Deshalb bin ich ja ein Freund von Flow-APIs oder allgm Fluent Interfaces. Die machen nicht nur bei async Verarbeitung das Verständnis und die Notation einfacher.

Wer die Variablen b und c scheut, der könnte doch vielleicht so lesbarer schreiben:

C | B | A

Das ist in C# natürlich nicht so recht möglich. Wie wäre es jedoch mit:

Flow

.From(C)

.To(B)

.To(A)

.Execute();

Sieht für so ein kleines Beispiel etwas überkandidelt aus. Aber wenn die Szenarien größer werden, halte ich das für ein unterschätztes Programmiermodell.

Ich bedanke mich bei allen beteiligten für die anregende Diskussion. Ich finde es immer wieder schön, wenn ein einfacher Blogpsot so eine Diskussion losreißen kann.

DotNetKicks-DE Image
LINQ to XML: Queries auf XML mit Namespaces

Beim Zugriff auf XML mit bestimmten XML-Namespaces kommt es beim herkömmlichen Queries zu einem Fehler. Wie auch beim XMLDoxument muss beim den Abfragen auf bestimmte Knoten ein Namespace angegeben werden.

Ausgangspunkt bei mir ist eine Abfrage per WebDAV auf einen Exchange Server, bei der ich ungefähr folgende Antwort erhalte:
<?xml version="1.0" ?>
<a:multistatus
    xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"
    xmlns:d="urn:schemas:httpmail:"
    xmlns:c="xml:"
    xmlns:a="DAV:">
  <a:response>
    <a:href>http://mdomain/exchange/Account/</a:href> 
    <a:propstat> 
      <a:status>HTTP/1.1 200 OK</a:status> 
      <a:prop>
      </a:prop>
    </a:propstat>
  </a:response>
</a:multistatus>

Folgende Abfrage liefert einen Fehler:
XDocument xdoc = XDocument.Load(xmlResponseReader);
XElement xelement = xdoc.Element("a:multistatus");

XmlException: The ':' character, hexadecimal value 0x3A, cannot be included in a name.

Um das Element nun fehlerfrei zu erhalten muss es wie folgt abgefragt werden:
XDocument xdoc = XDocument.Load(xmlResponseReader);
XElement xelement = xdoc.Element("{DAV:}multistatus");

Damit haben wir den – aus meiner Sicht - ersten und einzigen, aber recht großen Nachteil von LINQ to XML gefunden: Die Namespaces müssen direkt in den Namen des Elements eingegeben werden.

Die Lösung die in der MSDN angeboten wird, ist auch nicht besser:
XDocument xdoc = XDocument.Load(xmlResponseReader);
XNamespace a = "DAV:";
XElement xelement = xdoc.Element(a + "multistatus");

Mir stellt sich hier die Frage: Wieso erstelle ich ein XNamespace-Object wenn ich es dann doch per String-Gebastel in den Elementnamen einbauen muss. Der Kommentator in der MSDN Dokumentation ist ganz offensichtlich der selben Meinung.

Peter hat für dieses Problem eine kleine elegante Lösung, indem er für die Methoden Element und Elements jeweils eine Extension Methode geschrieben hat:
public static IEnumerable<XElement> Elements(
    this XContainer source,
    XNamespace ns,
    string name)
{
  return source.Elements(ns + name);
}
public static XElement Element(
    this XContainer source,
    XNamespace ns,
    string name)
{
  return source.Element(ns + name);
}

So kann ich wenigstens außerhalb der Extension Methoden ohne String-Gebastel auskommen:
XDocument xdoc = XDocument.Load(xmlResponseReader);
XNamespace a = "DAV:";
XElement xelement = xdoc.Element(a, "multistatus");

René hat mich per Kommentar darauf hingewiesen, dass man die Elemente natürlich auch per XName abfragen kann. Das ganze sieht dann so aus:
XDocument xdoc = XDocument.Load(xmlResponseReader); 
XName xname = XName.Get("multistatus", "DAV:");
XElement xelement = xdoc.Element(xname);

DotNetKicks-DE Image
Sechstes Treffen des .NET-Stammtisch Konstanz-Kreuzlingen

Das sechste .NET-Stammtisch Treffen findet mit Thomas Schissler und folgendem Thema statt:

Überblick über VSTS 2010.

Mit Visual Studio Team System 2010 bring Microsoft eine neue Generation seiner Entwicklungsplattform auf den Markt.

Neben einer großen Anzahl von Verbesserungen bring VSTS 2010 und das Backendsystem TFS 2010 auch völlig neue Funktionen und Möglichkeiten mit. Der Vortrag beleuchtet die verschiedenen Bereiche und stellt jeweils die wichtigsten Neuerungen vor. Diese werden mit verschiedenen Praxisbeispielen plastisch erläutert.

Thomas ist Leiter die Software-Entwicklung bei der Artiso AG in Ulm, Gründungsmitglied und Team-Leader der .NET Developer-Group Ulm und MVP für den Bereich Team System. Desweiteren ist Thomas viel als Sprecher auf großen Konferenzen und in User Group unterwegs. Das Weblog von Thomas, mit vielen Beiträgen zum Thema VSTS, ist unter folgender URL zu finden: http://www.artiso.com/problog/

Änderung im Ablauf der Veranstaltungen
Wir halten es in Zukunft so, dass es bei jedem Treffen nur einen Vortrag gibt, anschließend jedoch genügend Zeit bleibt um bei einem Bierchen darüber zu diskutieren, damit die Teilnehmer auch aktiv werden und die Sprechern Feedback empfangen und zusätzliche Fragen beantworten können.

DotNetKicks-DE Image
Mehr Beiträge Nächste Seite »