Posts Tagged ‘.NET’

MSBuild: ZIP mit Versionsnummer

Thursday, September 4th, 2008

Um in einem MSBuild File eine ZIP Datei zu erstellen kann man die Community Task von http://msbuildtasks.tigris.org/ verwenden. Das sieht dann folgendermaßen aus (Danke an Ben Hall!):


<Target Name="Zip">
    <PropertyGroup>
        <BuildDir>$(MSBuildProjectDirectory)\MeinService</BuildDir>
    </PropertyGroup>


 

    <ItemGroup>
        <!-- DLL, EXE, PDB, *.config, keine *.vhost.exe -->
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.dll" />
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.exe" Exclude="*.vhost.exe" />
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.pdb" />
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.config" />
    </ItemGroup>

    <MakeDir Directories="$(BuildDir)\Builds"
        Condition="!Exists('$(BuildDir)\Builds')" />
    <Zip Files="@(ZipFiles)"
        WorkingDirectory="$(BuildDir)\bin\Debug\"
        ZipFileName="$(BuildDir)\Builds\MeinService.zip"
        ZipLevel="9" />
</Target>
 
Nun möchte ich noch die Versionsnummer einer der Assemblies im Dateinamen der ZIP Datei verwenden. Im Web findet man reichlich Hinweise auf Lösungen bei denen die Versionsnummer während des Build Prozess aktualisiert wird. Ich möchte aber die Versionsnummer in einer AssemblyInfo.cs Datei vorgeben und diese im Build Prozess weiterverwenden.
 
Dazu benötigt man weitere MSBuild Tasks:
http://www.codeplex.com/sdctasks. Darin ist nämlich der Task VersionNumber.LoadFileVersion enthalten mit dem man die Assembly Version aus einer DLL oder EXE auslesen kann. Das Ergebnis sieht dann wie folgt aus:
 
<Target Name="Zip">
    <PropertyGroup>
        <BuildDir>$(MSBuildProjectDirectory)\MeinService</BuildDir>
    </PropertyGroup>

    <ItemGroup>
        <!-- DLL, EXE, PDB, *.config, keine *.vhost.exe -->
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.dll" />
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.exe" Exclude="*.vhost.exe" />
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.pdb" />
        <ZipFiles Include="$(BuildDir)\bin\Debug\**\*.config" />
    </ItemGroup>

    <VersionNumber.LoadFileVersion
        FileName="$(BuildDir)\bin\Debug\MeinService.exe"
        VersionNamePath="$(BuildDir)\bin\Debug\">
        <Output TaskParameter="VersionNumber" PropertyName="versionNumber" />
    </VersionNumber.LoadFileVersion>

    <MakeDir Directories="$(BuildDir)\Builds"
        Condition="!Exists('$(BuildDir)\Builds')" />

    <Zip Files="@(ZipFiles)"
        WorkingDirectory="$(BuildDir)\bin\Debug\"
        ZipFileName="$(BuildDir)\Builds\MeinService.$(VersionNumber).zip"
        ZipLevel="9" />
</Target>
 
Das Einbinden der zusätzlichen MSBuild Tasks ist jeweils bei den Installationsanleitungen beschrieben und nicht weiter schwierig.
 
Technorati-Tags: ,

Expression Trees mit .NET Framework 2.0

Thursday, September 4th, 2008

Der C# 3.0 Compiler ist in der Lage Lambdas in Expression Trees zu übersetzen die dann zur Laufzeit zur Verfügung stehen. Leider ist das Sprachfeature an die Assembly System.Core.dll gebunden denn dort sind die erforderlichen Klassen für die Expression Trees abgelegt. Da die Assembly System.Core.dll zum .NET Framework 3.5 gehört kann man offiziell keine Expression Trees in Projekten verwenden die als Target Framework das .NET Framework 2.0 verwenden.

Bei den Extension Methods ist das ähnlich, jedoch ist hier die Abhilfe deutlich einfacher (man muss nur ein Attribut ExtensionAttribute im Namespace System.Runtime.CompilerServices bereitstellen welches vom Compiler als Tag verwendet wird).

Ich habe versucht die System.Core.dll mit dem Framework 2.0 zum Laufen zu bringen und siehe da, es geht!

Man kopiert sich die System.Core.dll aus dem Verzeichnis C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5 in ein Verzeichnis innerhalb seines Projektes und referenziert die lokale Kopie der Assembly. Anschließend setzt man folgende Properties der Assembly auf true:

  • Specific Version
  • Copy local

SystemCoreProperties

Nun findet der Compiler die erforderlichen Klassen und kann Lambdas in Expression Trees übersetzen. Auf diese Weise kann man z.B. das Fluent NHibernate Projekt mit dem .NET Framework 2.0 nutzen.

Die große Frage bleibt allerdings: ist das nach Microsofts Lizenzbestimmungen zulässig?

Kritische Betrachtung des Entity Framework

Thursday, September 4th, 2008

Die Folien zu meinem Vortrag Kritische Betrachtung des Entity Framework vom 02.09.2008 bei der .NET Usergroup Köln sind online.

Folien als PDF (4MB)

Technorati-Tags: ,

Soll ich von NUnit 2.4 auf xUnit umsteigen?

Saturday, August 2nd, 2008

Bislang verwende ich NUnit 2.4 in Verbindung mit ReSharpers integriertem Test Runner. Da xUnit ein Plugin für ReSharpers Test Runner mitbringt und Features wie Generics verwendet will ich heute mal damit “spielen” um zu sehen ob sich ein Umstieg lohnt.

Download und Installation

Das Projekt wird bei CodePlex gehostet. Download. Aktuell zum jetzigen Zeitpunkt ist v1.0.2 RC1. Der Download enthält ein ZIP Archiv das man in ein Verzeichnis seiner Wahl entpackt.

Um die diversen Test Runner zu installieren startet man anschließend xunit.installer.exe und aktiviert die Test Runner die man verwenden möchte. Ferner kann man Support für das ASP.NET MVC Framework einrichten. Das führt dazu dass Templates für xUnit Tests eingerichtet werden (habe ich nicht weiter ausprobiert).

xUnitInstaller

Projekt einrichten

Ich baue meine Projekte generell so auf, dass ich im Basisverzeichnis ein Verzeichnis Vendor anlege. Dort hinein kommen alle externen Abhängigkeiten, jede in ihr eigenes Unterverzeichnis. Im Falle von xUnit kopiere ich also folgende Dateien in das Verzeichnis Vendor\xUnit:

  • xunit.dll / xunit.xml
    xUnit Core
  • xunitext.dll / xunitext.xml
    Erweiterungen für z.B. datengetriebene Tests
  • xunitext35.dll / xunitext35.xml
    Extension Methods die .NET Framework 3.5 voraussetzen

Erste Ernüchterung

Der erste Schock: gibt es kein Assert.That? Nein gibt’s nicht. Zurück zur alten Assert.AreEqual Syntax? Nein, das wäre definitiv ein K.O. Kriterium gegen xUnit. Aber der Reihe nach…

Seit NUnit 2.4 verwende ich die Assert.That Syntax:

Assert.That(kunde.KreditLimit, Is.EqualTo(400));

Vor allem die Möglichkeit alle Constraints mit einem Not zu ergänzen finde ich sehr schön:

Assert.That(kunde.EMail, Is.Not.Null);

Ich finde diese neue Syntax deutlich lesbarer als die “alte”:

Assert.AreEqual(400, kunde.KreditLimit);

Tja, die Entwickler von xUnit sehen das leider anders :-(

Es gibt noch die Extension Methods aus der Assembly xunitext35.dll. Mal sehen ob ich damit klar komme:

kunde.Name.ShouldEqual("Lieser");

Damit könnte ich mich wohl anfreunden. Aber dadurch wird die Umstellung von existierenden NUnit Tests nicht gerade einfach. Und wir haben mehrere Tausend davon…

Exceptions

Eine riesen Verbesserung gegenüber NUnit 2.4 ist Assert.Throws. Oft ist es erforderlich einen Test zu schreiben der prüft ob eine bestimmte Exception ausgelöst wird. Der Weg von NUnit, dies mit dem Attribut ExpectedException zu lösen, hat einen ganz gravierenden Nachteil: es wird nur sichergestellt dass irgendwo in meinem Test die Exception ausgelöst wird. Das ist in vielen Fällen zu grob und kann mit der neuen Assert.Throws Syntax eleganter gelöst werden:

Assert.Throws<ArgumentNullException>(() => kunde.Name = null);

Gibt es diese Syntax auf für NUnit? Google ist dein Freund… NUnit 2.5 hat’s, ist aber noch nicht “production ready”. James Newkirk hat eine Implementierung von Assert.Throws veröffentlicht die auch mit NUnit 2.4 eingesetzt werden kann.

Fazit

xUnit wäre im Prinzip das Unit Test Framework meiner Wahl:

  • ReSharper Unit Test Runner wird unterstützt
  • Bewusst einfach gehalten
  • Assert.Throws

Dagegen spricht die fehlende Assert.That Syntax. Ferner müsste ich den Continuous Integration Prozess umstellen. xUnit bietet Support für Cruise Control .NET, aber von alleine richtet sich das schließlich nicht ein ;-)

So werde ich erst mal bei NUnit bleiben und das oben erwähnte Assert.Throws verwenden bis NUnit 2.5 “production ready” ist.

Technorati-Tags: ,

Spartanisch Programmieren

Tuesday, July 22nd, 2008

Jeff Atwood hat einen Beitrag geschrieben dem ich mich voll und ganz anschließen kann: Programmiere spartanisch!

Im Laufe der Zeit hat sicher jeder Software Entwickler seinen persönlichen Stil weiter entwickelt. Was mir persönlich dabei sehr geholfen hat und weiterhin hilft ist das Lesen fremden Codes. In Zeiten von Open Source ist es kein Problem sich dazu mit “Futter” zu versorgen. Lesen von fremdem Code dient mir dazu zu reflektieren was ich am jeweiligen Code gut bzw. schlecht finde.

So befolgte ich früher z.B. die “single exit” Regel die besagt, dass eine Methode nur an einer Stelle verlassen werden sollte. Zu C++ Zeiten war das ein Rat der zumindest nicht ganz in die falsche Richtung führte wenn man an die Probleme der “Speicherverwaltung zu Fuß” denkt. Heute plädiere ich vehement für “fast exit”. In einer Methode prüfe ich zunächst alle Voraussetzungen die erfüllt sein müssen und verlasse die Methode sofort sobald eine der Voraussetzungen nicht erfüllt ist. Im Ergebnis nimmt die Schachtelungstiefe ab, der Code wird lesbarer.

Vereinfacht dargestellt (Pseudocode):

public void DoSomething() {
  if (a) {
    if (b) {
      if (c) {
        DoItRealy();
      }
    }
  }
}

public void DoSomething() {
  if (!a) {
    return;
  }
  if (!b) {
    return;
  }
  if (!c) {
    return;
  }

  DoItRealy();
}

Zu dieser und ähnlichen Erkenntnissen kann man gelangen, in dem man fremden Code studiert. Schneller kommt man vermutlich voran wenn man sich (zusätzlich!) mit Empfehlungen anderer Software Entwickler auseinandersetzt. Eine schöne Gelegenheit dazu bietet dieser Text über spartanisches Programmieren.

So sind z.B. die beiden folgenden Betrachtungsweisen über Komplexität sehr nützlich:

  • Horizontal: Verschachtelungstiefe von Kontrollstrukturen sowie Zeilenlänge
  • Vertikal: Anzahl Zeilen einer Methode oder Klasse

Bei der Anzahl von Zeilen und der Zeilenlänge bemühe ich mich schon lange diese zu reduzieren. Die Verschachtelungstiefe dagegen  habe ich noch nicht so lange im Blickfeld.

Software Design Principles – On Tour

Monday, July 21st, 2008

An folgenden Terminen werde ich meinen Vortrag über Software Design Principles halten:

 

Technorati-Tags:

Software Design Principles Vortrag

Wednesday, June 25th, 2008

Gestern Abend habe ich in Bonn bei der .NET Usergroup Bonn-to-Code den Vortrag Software Design Principles gehalten. Die Folien stehen als PDF zum Download (4MB) zur Verfügung.

Technorati-Tags: ,,,,

Vortrag "Software Principles" bei Bonn-to-Code

Wednesday, June 18th, 2008

Am kommenden Dienstag 24.06.2008 um 19:00 halte ich bei Bonn-to-Code meinen Vortrag über Software Principles. Den Vortrag habe ich im letzten Jahr schon hier in Köln bei der .NET User Group gehalten, ihn aber zwischenzeitlich heftig überarbeitet.

Das liegt daran dass ich Presentation Zen von Garr Reynolds gelesen habe. Dieses Buch kann ich jedem empfehlen der Vorträge oder Präsentationen hält. Allerdings ist nach dem Lesen nichts mehr wie es war ;-) Spiegelstrichlisten in PowerPoint sind passé. Überhaupt muss man seine Arbeit mit PowerPoint überdenken. Garr Reynolds unterhält auch einen Blog zum Thema. Sehr lesenswert!

Ich bin jedenfalls gespannt auf den Vortrag und freue mich auf euer Feedback!

ReSharper 4.0 ist fertig

Tuesday, June 10th, 2008

JetBrains hat ReSharper 4.0 fertiggestellt. Ich verwende ReSharper 4.0 seit dem ersten öffentlichen nightly build und kann nur sagen dass JetBrains damit ein Spitzenprodukt weiter verbessert hat. Das wichtigste Feature ist natürlich die Unterstützung aller C# 3.0 Sprachelemente (Lambdas, Extension Methods, LINQ, etc.). Darüber hinaus gibt es neue Features wie z.B.

  • Inline Method: Gegenstück zu Extract Method. Nun kann man beim Refactoring endlich den Rumpf einer Methode inline an den Verwendungsstellen einfügen.
  • Complete Statement: mit Ctrl + Shift + Enter wird die Zeile syntaktisch vervollständigt und der Cursor in die nächste Zeile bewegt. Sehr nützlich bei der Eingabe von if-Statements etc.
  • ASP.NET Performance Verbesserungen: ReSharpers Performance beim Umgang mit ASP.NET Projekten wurde verbessert. Auch der Speicherbedarf wurde reduziert.

Wer ReSharper noch nicht kennt sollte schleunigst hier den Download starten und R# 30 Tage testen. Aber Vorsicht! Suchtgefahr ;-)

Wer mit NHibernate arbeitet sollte zusätzlich mein NHibernate Plugin in Betracht ziehen. Derzeit ist das Projekt noch im Alphastadium aber bereits so stabil dass ich es produktiv im Einsatz habe.

Technorati-Tags: ,

IStateProvider für den Zugriff auf die Session

Thursday, May 22nd, 2008

Vor ein paar Tagen habe ich hier beschrieben wie man den Zugriff auf die Session in ASP.NET MVC Controllern abstrahieren kann. Während meines Vortrags in Bonn zum ASP.NET MVC hat mich ein aufmerksamer Zuhörer darauf hingewiesen dass meine Implementierung ein Problem hat wenn sie in mehr als einem Controller verwendet wird. Hier nochmal die ursprüngliche Implementierung:

public class StateProvider<T> : IStateProvider<T> where T : new()
{
    private const string StateKey = "state";

    public T GetState(Controller controller) {
        if (controller.HttpContext.Session[StateKey] == null) {
            SetState(controller, new T());
        }
        return (T)controller.HttpContext.Session[StateKey];
    }

    public void SetState(Controller controller, T state) {
        controller.HttpContext.Session[StateKey] = state;
    }
}

Das Problem ist der StateKey der verwendet wird um auf das Dictionary der Session zuzugreifen: wenn zwei Controller den StateProvider verwenden überschreiben sie sich gegenseitig ihre Daten.

Damit jeder Controller seinen eigenen Bereich in den Sessiondaten erhält kann man z.B. den Typnamen des Controllers verwenden:

public class StateProvider<T> : IStateProvider<T> where T : new()
{
    public T GetState(Controller controller) {
        if (controller.HttpContext.Session[StateKey(controller)] == null) {
            SetState(controller, new T());
        }
        return (T)controller.HttpContext.Session[StateKey(controller)];
    }

    public void SetState(Controller controller, T state) {
        controller.HttpContext.Session[StateKey(controller)] = state;
    }

    private static string StateKey(Controller controller) {
        return controller.GetType().ToString();
    }
}