Archiv

Artikel getaggt mit ‘Tools’

GitHub for Windows – oder Git einmal einfach

Die Versionsverwaltung Git wird unter Windows immer noch zurückhalten eingesetzt. Auch wenn man mit Helfern wie der Console 2 vieles einfacher machen kann, so bleibt Git doch ein komplexes Kommandozeilen-Tool. Die grafischen Oberflächen konnten einem meist auch nicht wirklich überzeugen – fehlende Befehle und Beschriftungen wie von Subversion her störten den Arbeitsfluss zu sehr.

Dieses Problem fiel auch GitHub auf. Eine Firma die ihr Geld mit Dienstleistungen rund um Git verdient möchte natürlich überall präsent sein. Da es an einem guten GUI für Windows fehlte, machte man halt selber eines.

 

Installation

GitHub for Windows lässt sich von http://windows.github.com/ herunterladen. Im *.exe ist ein Installer verpackt der Git in einer Sandbox installiert. Damit kann man problemlos Git installieren und braucht sich um sein System keine Gedanken zu machen – dies bleibt bis auf die Desktop-Icons unangetastet.

Idealerweise erzeugt man nebenher einen Account bei GitHub und verbindet sich gleich mit diesem. Dies ist nicht notwendig um die Applikation zu nutzen, man hat so aber gleich alle Einstellungen im Client und muss nichts mehr von Hand anpassen.

 

Klonen leicht gemacht

Wie man erwarten darf wurde die Anwendung sehr gut in GitHub integriert. Schaut man sich nun ein Projekt auf GitHub.com an, sieht man in seinem Browser (Firefox, IE und Chrome) den Knopf [Clone in Windows]:

Ein Klick darauf genügt und GitHub for Windows öffnet sich und klont das gerade ausgewählte Repository auf den Rechner.

 

Neues Repository anlegen

Ein neues Repository kann man genau so einfach anlegen wie eines zu klonen. Man kann entweder den Knopf [add] auf der Übersichtsseite anklicken oder den Ordner der als neues Repository geführt werden soll auf die Anwendung ziehen. Der einfach gehaltene Dialog ermöglicht einem einen Namen und eine Beschreibung zu vergeben. Wählt man die Option „Push to GitHub“ wird auch gleich alles konfiguriert um das Repository auf GitHub zu veröffentlichen.

Neben dem .git Ordner wird in diesem Schritt ebenfalls eine .gitignore und .gitattributes Datei angelegt. So werden automatisch all die temporären und benutzerspezifischen Dateien ausgeschlossen, die man meist nicht veröffentlichen will. (Will man diese Dateien doch drin haben kann man .gitignore selber anpassen.)

 

Änderungen speichern und anschauen

Nachdem man seine Änderungen gemacht hat geht es an den commit. Dazu öffnet man das Repository in GitHub for Windows und sieht auf einen Blick was sich verändert hat:

Nach dem man eine passende Beschreibung eingetragen hat genügt es auf [commit] zu klicken und die Änderungen sind als neue Version gespeichert.

Der gleiche Dialog dient einem auch um die Änderungen zu verfolgen. Dazu wählt man in der rechten Spalte die gewünschte Version und sieht alle veränderten Dateien mit den Anpassungen.

 

Änderungen publizieren

Wer seine Arbeit veröffentlichen will wird auch hier von GitHub for Windows unterstützt. Dazu genügt auf dem Repository ein Klick auf [push to github]. Im Dialog genügt es den Namen zu überprüfen (und bei Bedarf zu ändern) und mit einem weiteren Klick auf [push] wird das Repository zu GitHub hochgeladen:

Hat man dies einmalig gemacht genügt ein Klick auf [sync] um die lokale Arbeitsversion mit dem Repository auf GitHub abzugleichen.

 

Wenn mal etwas schiefläuft

Nicht immer gelingen einem allen Änderungen im ersten Anlauf. GitHub for Windows hat dafür auf der Repository-Seite 2 hilfreichen Funktionen:

  • [Revert commit] erzeugt einem die Gegenaktion zum gemachten Commit. Was man dort gelöscht hatte ist nun wieder drin und was hinzugekommen ist wird entfernt.
  • [Rollback to this commit] verwirft alle Änderungen zurück bis zur ausgewählten Version. Ist dies die letzte Version kann man den letzten Commit nochmals verändern. Andernfalls löscht es alle Änderungen die seit der ausgewählten Version gemacht wurden.

Genügt einem dies nicht kann man über [Tools] / [open a shell here] auf der Kommandozeile auf alle Git-Befehle zurückgreifen.

 

Nicht nur GitHub

Mit GitHub for Windows kann man jedes beliebige Git-Repository verwalten. Da GitHub private Repositories nur gegen Bezahlung anbietet greife ich gerne auf den Service von Bitbucket zurück.
Um das Repository mit Bitbucket zu verknüpfen muss man den Settings-Dialog auf dem Repository öffnen und die URL gemäss den Angaben von Bitbucket einfügen. Von da an gehen alle Aktionen genauso wie sie auch mit GitHub laufen.

 

Fazit

GitHub for Windows ist aus meiner Sicht der derzeit beste Client für Git auf Windows. Die Funktionalität der GUI-Anwendung deckt das ab was man als „normaler“ Anwender mit Git machen will. Soll es doch einmal nicht genügen stehen einem mehrere konfigurierte Konsolen zur Verfügung.

Das problemlose Zusammenspiel mit anderen Hostern wie Bitbucket macht dieses Tool auch für all diejenigen interessant, die nicht mit GitHub arbeiten wollen.

Kategorien:.Net, git Schlagworte: ,

Schnellere Webanwendungen dank MiniProfiler

Performance-Probleme bemerkt man meist erst dann wenn es zu spät ist – in der Produktion. Die kleine Menge an Testdaten auf dem Entwicklungssystem verzeihen einem so manche Unachtsamkeit und Ressourcenverschwendung. Unnötige SQL-Abfragen und die Select N+1 Problematik könnte man schon früh erkennen. Nur wer nimmt sich die Zeit immer den Profiler zu starten und alles zu überprüfen?

Wäre es nicht toll wenn im Hintergrund immer ein Profiler laufen und einem mit den Auswertungen versorgen würde? So könnte man immer mal wieder einen Blick aufs Ergebnis werfen und bei lange dauernden Aktionen gleich sehen wo die Ursache liegt. Tönt dies zu schön um wahr zu sein?

MiniProfiler bietet einem genau diese Funktionalität für ASP.Net und ASP.Net MVC Anwendungen. Dieser Profiler stammt von Stack Exchange und hilft dort beim optimieren aller Seiten der Stack Overflow-Familie.

 

Installieren

Die Installation von MiniProfiler erfolgt über NuGet. Wie immer kann man über die grafische Oberfläche das Paket suchen und installieren oder man nutzt die Konsole:

Install-Package MiniProfiler

 

Aktivieren

Um dem Profiler den Anfang und das Ende eines Requests mitzuteilen muss man die Datei Global.asax um diese beiden Methoden Erweitern:

protected void Application_BeginRequest()
{
    if (Request.IsLocal)
    {
        MiniProfiler.Start();
    }
}

protected void Application_EndRequest()
{
    MiniProfiler.Stop();
}

Damit auch etwas angezeigt wird muss die Datei \Views\Shared\_Layout.cshtml direkt vor dem schliessenden Body-Tag mit einem Aufruf zum Rendern der Resultate ergänzt werden:

    @StackExchange.Profiling.MiniProfiler.RenderIncludes() 
  </body>
</html>

Will man MiniProfiler in einem Webforms-Projekt einsetzten ist der Header in der Datei Site.Master so zu ergänzen:

<%= StackExchange.Profiling.MiniProfiler.RenderIncludes() %>
</head>

Bei mir war zudem noch eine Anpassung im web.config nötig:

<system.webServer>
  ...
  <handlers>
    <add name="MiniProfiler" path="mini-profiler-resources/*" verb="*" type="System.Web.Routing.UrlRoutingModule" resourceType="Unspecified" preCondition="integratedMode" />
  </handlers>
</system.webServer>

 

Auswerten

Sobald man die Webanwendung neu kompiliert und gestartet hat erscheint eine kleine Box in der linken oberen Ecke der Seite:

MiniProfiler beschränkt sich nicht nur aufs anzeigen der Ladezeit. Klickt man auf die Box wird ein detaillierter Report angezeigt:

Neben den allgemeinen Informationen über die Dauer des Request und die Dom Events kann man auch eigene Schritte definieren. Dazu setzt man den zu überwachenden Code in einen Using-Block und benennt den Step mit einem prägnanten Titel:

using (MiniProfiler.Current.Step("Step Set Message"))
{
  ViewBag.Message = "Your contact page.";
  Thread.Sleep(100);
}

Normalerweise werden die Ereignisse die keine relevante Zeit verbrauchen ausgeblendet. Fehlt einem der gesuchte Schritt kann man über den Link „show trivial“ das anzeigen aller Einträge erzwingen.

 

EF-Abfragen überprüfen

Richtig praktisch wird MiniProfiler wenn man auch gleich noch die Datenbankabfragen anzeigen kann. Dazu muss man zusätzlich das Paket MiniProfiler.EF installieren und Application_Start() in der Global.asax um einen Aufruf zur Initialisierung ergänzen:

MiniProfilerEF.Initialize();

Von nun an wird neben der Dauer der Aktionen die Anzahl darin ausgeführten SQL-Abfragen angezeigt:

Von dieser Zusammenfassung aus genügt 1 Klick und man sieht was genau für SQL-Befehle auf die DB losgelassen wurden:

Der Hinweis auf doppelte Abfragen oder Select N+1 ist äusserst hilfreich und hilft einem die gröbsten Schnitzer einfach zu finden.

 

Fazit

MiniProfiler ist schnell installiert und sehr einfach zu konfigurieren. Die Ladezeit als eine der wichtigsten Kennzahlen steht einem von nun an jederzeit und gut sichtbar zur Verfügung. Zusätzliche Informationen lassen sich mit geringem Aufwand hinzufügen und ermöglichen einen Einblick ins Innere der Anwendung.

Meiner Meinung nach ist dieses kleine Tool ein tolles Hilfsmittel um schon zur Entwicklungszeit die Ursachen der häufigsten Produktionsprobleme anzugehen.

Kategorien:.Net Schlagworte:

Meine Werkzeugliste

25. September 2012 2 Kommentare

Es sind ja meist die ganz kleinen Werkzeuge die einem die Arbeit erleichtern und die sind so simpel dass man sie kaum je erwähnt. Startet man in einer neuen Umgebung sind diese Werkzeuge aber meist das erste was man installiert um sich wieder „zu Hause“ zu fühlen.

Dies hier ist meine Liste mit diesen kleinen Tools und Anwendungen die ich für meine tägliche Arbeit einsetze. Die Idee dazu habe ich von Scott Hanselman und Piotr Kwapin. Wer seine Tools beisteuern möchte kann diese gerne via Kommentar tun.

 

Windows

IrfanView ist ein leichtgewichtiger und schneller Bildbetrachter. Mit den eingebauten Funktionen kann man aber auch direkt einen Scanner ansprechen oder eine Batchverarbeitung starten.

7-Zip ist eine Open Source Alternative zu WinZip. Neben *.zip können auch *.tar und *.rar Dateien entpackt werden. Das Tool ist sehr praktisch wenn man betriebssystemübergreifend arbeiten muss.

Notepad++ ist der Texteditor den ich jeweils als erstes Programm auf einem neuen Gerät installiere. Neben Syntaxhervorhebung für fast alle Sprachen unterstützt Notepad++ auch allerlei Zeilenumbrüche und Kodierungen.

ZoomIt ist ein Miniprogramm für Präsentationen. Will man etwas auf dem Monitor zeigen erlaubt ZoomIt das heranzoomen und markieren.

Microsoft Security Essentials ist ein für den Privatgebrauch kostenloser Virenschutz. Läuft bei mir ohne Probleme und ohne Geschwindigkeitseinbussen.

Foxit Reader ist eine schlanke Alternative zum Adobe Reader fürs Anzeigen von PDF-Dateien.

Greenshot liefert alles was man für Screenshots und deren Bearbeitung (wie Hervorhebungen und Pfeile) benötigt.

 

Visual Studio und .Net

ReSharper ist eine äusserst hilfreiche Erweiterung für Visual Studio die viele kleine Unschönheiten behebt und eine sehr praktische Codeanalyse liefert.

NuGet ist ein Paketmanager für Visual Studio der es erlaubt sehr einfach Bibliotheken in sein Programm aufzunehmen. Mit NuGet entfällt zudem das eigenhändige Auflösen der Abhängigkeiten. (Kurzanleitung)

VisualSVN ist meine Wahl um mit SVN-Projekten in Visual Studio zu arbeiten. Die Integration ist sehr gut und man behält die Kontrolle über die einzelnen Aktionen. Dieser Luxus ist mit $49 nicht gratis aber sein Geld wert.

Indent Guides ist eine Erweiterung für Visual Studio zum Visualisieren der Einrückungen. Bei Code mit sehr vielen Verschachtelungen ist diese Erweiterung äusserst Hilfreich.

LINQPad ist ein Editor mit dem man LINQ-Abfragen testen kann. Dadurch dass man nicht mehr für jede Änderung den Code neu kompilieren muss kann man sehr schnell arbeiten und Probleme finden. Ein meiner Meinung nach unverzichtbares Werkzeug auch fürs testen von OData-Abfragen oder zur Zertifizierungsvorbereitung. (Kurzanleitung)

SQL Complete ist ein kostenloses Plug-In um das SQL Server Management Studio mit IntelliSense zu erweitern. Schreibt man SQL-Abfragen von Hand ist dies eine enorme Erleichterung.

 

Web

Firefox ist ein schneller Webbrowser der sich mit Add-ons beliebig erweitern lässt. Wer mit dem Internet Explorer unzufrieden ist sollte sich Firefox anschauen.

FireBug ist eine Erweiterung zu Firefox für Webentwickler. Der ausgereifte JavaScript Debugger, ein verständlicher Profiler und die sehr einfache Anzeige der verschachtelten CSS-Formatierungen machen FireBug zu einem unverzichtbaren Werkzeug.

YSlow analysiert Webseiten hinsichtlich der Performance. Als Grundlage dienen 23 Empfehlungen des Performance-Teams von Yahoo die man unbedingt beachten sollte.

Internet Explorer Developer Toolbar ist eine Erweiterung die vergleichbar mit FireBug für Firefox ist. Obwohl noch nicht ganz so ausgereift wie FireBug ist es doch ein nützliches Tool zum abklären IE-spezifischer Probleme.

Chrome ist ein sehr schneller Webbrowser von Google. Das direkte absetzen von Suchabfragen in der Adressleiste und die mächtige JavaScript-Konsole sind sehr praktisch und nur zwei von vielen Funktionen.

WireShark kommt bei mir immer dann zum Einsatz wenn ich schauen muss was genau über das Kabel übertragen wird. Als letzter Zufluchtsort fürs Debuggen ist WireShark sehr hilfreich, es braucht aber einiges an Hintergrundwissen.

 

Webseiten und Services

Stack Overflow ist meine Anlaufstelle bei Programmierproblemen. Die Frage-und-Antwort Seite bietet eine zeitgemässe Variation der bekannten Web Foren und Newsgroups.

Gist ist eine sehr einfache Möglichkeit zum Veröffentlichen von Code-Schnipsel. Neben der sprachabhängigen Syntaxhervorhebung ist jedes Gist auch ein vollwertiges Git-Repository. (Kurzinfo)

DropBox bietet einen benutzerfreundlichen Weg zum Synchronisieren von Dateien zwischen verschiedenen Computern. Sensitive Daten sollte man vor dem hochladen aber mit geeigneten Mitteln selber verschlüsseln.

PortableApps.com liefert eine ganze Reihe von Programmen zum Ausführen direkt ab einem USB-Stick. Da eine Installation entfällt laufen diese Programme häufig auch dort wo man keine Schreibrechte fürs Programmverzeichnis hat.

Instapaper ermöglicht einem das markieren von Webseiten zum späteren Lesen. Durch das Entfernen der Werbung sind die Seiten auch problemlos auf kleineren Displays (wie einem Smartphone oder Kindle) darstellbar.

Kategorien:.Net, Tools, webDotNet Schlagworte:

Moq für komplexere Anwendungsfälle

Moq ist eine kleine Mock-Bibliothek, die ich hier bereits einmal vorgestellt habe. Für die meisten Anwendungsfälle genügt es die Rückgabewerte von Methoden zu beeinflussen. Ab und zu wäre es aber praktisch ein wenig mehr mit den Mocks machen zu können. Heute zeige ich wie Moq einem bei spezielleren Anwendungsfällen unterstützen kann.

 

Flexible Rückgabewerte

Mit Moq ist es kein Problem verschiedene Rückgabewerte zu liefern – so lange sich die Parameter beim Methodenaufruf unterscheiden. Der notwendige Code um den Wert „A“ für die Id 1 und „B“ für die Id 2 zu erhalten sieht so aus:

public interface ISimpleDemo
{
    string GetValue(int id);
}

[TestMethod]
public void MultipleReturnsForDifferentInputs()
{
    var mock = new Mock<ISimpleDemo>();
    mock.Setup(service => service.GetValue(1)).Returns("A");
    mock.Setup(service => service.GetValue(2)).Returns("B");

    Assert.AreEqual("A", mock.Object.GetValue(1));
    Assert.AreEqual("B", mock.Object.GetValue(2));
}

Hin und wieder steht man aber vor der Aufgabe bei einer Methode ohne Parameter verschiedene Rückgabewerte definieren zu müssen. Der direkte Versuch die gewünschten Werte nach einander zu definieren schlägt leider fehl:

public interface IBlogDemo
{
    string GetNextName();
}

[TestMethod]
public void MultipleReturnsTheWrongWay()
{
    var mock = new Mock<IBlogDemo>();
    mock.Setup(service => service.GetNextName()).Returns("A");
    mock.Setup(service => service.GetNextName()).Returns("B");
    mock.Setup(service => service.GetNextName()).Returns("C");

    Assert.AreEqual("A", mock.Object.GetNextName()); // Gibt "C"
    Assert.AreEqual("B", mock.Object.GetNextName());
    Assert.AreEqual("C", mock.Object.GetNextName());
}

So überschreibt man nur den Rückgabewert und der Tests endet mit dieser Fehlermeldung:

Assert.AreEqual failed. Expected:<A>. Actual: <C>.

Damit man diesen Test erfüllen kann benötigt es einen anderen Ansatz. Mit Hilfe einer Queue kann man die Werte in der gewünschten Reihenfolge ablegen (auch null-Werte sind so möglich). Die Returns-Funktion von Moq ruft nun die Dequeue-Methode auf und bekommt die für den Test benötigten Werte zurück:

[TestMethod]
public void MultipleReturnsRight()
{
    var mock = new Mock<IBlogDemo>();
    var results = new List<string> {"A", "B", "C", null};
    var pq = new Queue<string>(results);

    mock.Setup(c => c.GetNextName()).Returns(pq.Dequeue);

    Assert.AreEqual("A", mock.Object.GetNextName());
    Assert.AreEqual("B", mock.Object.GetNextName());
    Assert.AreEqual("C", mock.Object.GetNextName());
    Assert.IsNull(mock.Object.GetNextName());
    // ==> Funktioniert
}

 

Wurde eine Methode aufgerufen?

Moq bietet einem die Möglichkeit einzelne Aspekte des verwendeten Mocks zu überprüfen. Muss man wissen wie oft eine Methode des Mocks aufgerufen wurde ist die Funktion Verify sehr hilfreich. Der notwendige Code um zu prüfen ob GetValue mit Parameter 1 genau einmal aufgerufen wurde wird so sehr einfach:

[TestMethod]
public void ExactlyOnceCalled()
{
    var mock = new Mock<ISimpleDemo>();

    mock.Object.GetValue(1);

    mock.Verify(db => db.GetValue(1), Times.Once());
}

Wird die Methode nicht mit dem erwarteten Parameter aufgerufen (zum Beispiel in dem man im oberen Code-Ausschnitt GetValue mit dem Wert 2 aufruft), wirft Moq eine entsprechende Fehlermeldung:

Test method TestProject1.UnitTest1.ExactlyOnceCalled threw exception:
Moq.MockException:
Expected invocation on the mock once, but was 0 times: db => db.GetValue(1)
No setups configured.
Performed invocations:
ISimpleDemo.GetValue(2)

Es kann vorkommen das man nicht genau weiss mit welchem Parameter die Methode aufgerufen wurde (wenn beispielsweise in der zu testenden Klasse neue Instanzen erzeugt werden). In diesem Fall kann man die It-Klasse verwenden:

[TestMethod]
public void ExactlyOnceCalledUnknownParameter()
{
    var mock = new Mock<ISimpleDemo>();

    mock.Object.GetValue(1);

    mock.Verify(db => db.GetValue(It.IsAny<int>()), Times.Once());
}

Auch bei der Anzahl der Aufrufe ist Moq sehr flexibel. Ob eine Methode einmal, nie, genau x mal oder innerhalb eines Bereiches aufgerufen wurde kann man alles mit der Times-Klasse überprüfen lassen:

[TestMethod]
public void TimesHasManyUsages()
{
    var mock = new Mock<ISimpleDemo>();

    mock.Object.GetValue(1);
    mock.Object.GetValue(2);
    mock.Object.GetValue(2);

    mock.Verify(db => db.GetValue(1), Times.Once());
    mock.Verify(db => db.GetValue(2), Times.AtLeastOnce());
    mock.Verify(db => db.GetValue(2), Times.Between(1, 2, Range.Inclusive));
    mock.Verify(db => db.GetValue(2), Times.Between(1, 3, Range.Exclusive));
    mock.Verify(db => db.GetValue(2), Times.Exactly(2));
    mock.Verify(db => db.GetValue(3), Times.Never());
}

 

Fazit

Moq unterstützt einem auch bei komplexeren Einsatzszenarien. Die Möglichkeiten von Verify sind vielfältig und können einem dabei helfen so manches Testszenario abzudecken. Dabei sind It.IsAny und Times eine grosse Hilfe.

Allerdings darf man bei so viel Flexibilität das Ziel des Tests nicht aus den Augen verlieren. Sobald man sich auf zu viele Implementationsdetails einlässt werden die Tests sehr schnell unwartbar. Im Zweifel sollte man daher lieber erst versuchen mit einer besseren Code-Struktur den Test einfacher zu gestalten.

Kategorien:.Net, Software Entwicklung, webDotNet Schlagworte: ,

Weniger Code dank AutoMapper

AutoMapper ist ein einfach zu verwendender Objekt-Objekt Mapper. Wer mehr als einmal ein Geschäftsobjekt auf ein DTO oder Viewmodel abbilden musste dachte sich wohl: Warum muss ich diesen Code selber schreiben? Mit AutoMapper gibt es genau dafür eine Lösung.

 

Installation

Wie bei fast allen Bibliotheken kann man auch hier wieder NuGet zur Installation verwenden. Wer die Package Manager Konsole der GUI-Anwendung vorzieht bekommt AutoMapper mit diesem Befehl:

PM> Install-Package AutoMapper

 

Ausgangslage mit ganz einfachen Daten

Als Beispiel für den manuellen Weg wie man ein Objekt auf ein anderes überträgt dienen uns die beiden Klassen Basic und BasicDto:

public class Basic
{
    public string A { get; set; }
    public string B { get; set; }
    public string C { get; set; }
}

public class BasicDto
{
    public string A { get; set; }
    public string B { get; set; }
}

private readonly Basic basic = new Basic() { A = "[A]", B = "[B]", C = "[C]" };

Bisher werden die meisten Entwickler wohl einen Code geschrieben haben der diesem hier sehr ähnlich ist:

[TestMethod]
public void MappingTheOldWay()
{
    BasicDto dto = new BasicDto();
    dto.A = basic.A;
    dto.B = basic.B;

    Assert.AreEqual("[A]", dto.A);
    Assert.AreEqual("[B]", dto.B);
}

Mit AutoMapper muss man erst ein Mapping definieren und danach das gewünschte Ausgangsobjekt übergeben:

[TestMethod]
public void MappingSimpleObjectWithAutomapper()
{
    Mapper.CreateMap<Basic, BasicDto>();

    BasicDto dto = Mapper.Map<Basic, BasicDto>(basic);

    Assert.AreEqual("[A]", dto.A);
    Assert.AreEqual("[B]", dto.B);
}

So lange man nur wenige Werte übertragen muss ist ein Helfer wie AutoMapper zugegebenermassen kein grosser Gewinn. Anders sieht es aus wenn die Objekte komplexer und umfangreicher werden.

 

Nicht alle Werte automatisch übernehmen

Per Konvention werden automatisch alle Werte übernommen bei denen im Ausgangs- und im Zielobjekt ein Feld mit gleichem Namen existiert. Will man dieses Verhalten ändern kann man AutoMapper sehr einfach anpassen:

[TestMethod]
public void MappingNotAllValues()
{
    Mapper.CreateMap<Basic, BasicDto>()
        .ForMember(dest => dest.B, opt => opt.Ignore());

    BasicDto dto = Mapper.Map<Basic, BasicDto>(basic);

    Assert.AreEqual("[A]", dto.A);
    Assert.IsNull(dto.B);
}

Mit dest wir hier das Zielobjekt (Destination) referenziert und für das Property B eine entsprechende Option (opt) gesetzt. Die Bezeichner „dest“ und „opt“ kann man nach Belieben umbenennen. Ich halte mich hier an die im Wiki verwendeten Namen.

 

Werte verändern

AutoMapper lässt einem Werte nicht nur direkt übernehmen, sondern erlaubt einem auch diese nach Belieben zu verändern:

[TestMethod]
public void MappingModifyValues()
{
    Mapper.CreateMap<Basic, BasicDto>()
        .ForMember(dest => dest.A, 
            opt => opt.MapFrom(src => String.Format("{0} {1}", src.A, src.C)));

    BasicDto dto = Mapper.Map<Basic, BasicDto>(basic);

    Assert.AreEqual("[A] [C]", dto.A);
    Assert.AreEqual("[B]", dto.B);
}

Wie viel Funktionalität man in ein Mapping stecken will sollte man sich aber gut überlegen. Bei zu vielen Sonderfällen hat man immer noch die Möglichkeit selber den passenden Code zu schreiben und für diesen Fall auf AutoMapper zu verzichten.

 

Verschachtelte Objekte

Richtig interessant wird es wenn das Ausgangsobjekt aus mehreren Objekten besteht. Benennt man die Felder im Zielobjekt nach dem Muster KlassennameFeldname übernimmt AutoMapper wiederum die ganze Arbeit:

public class Customer
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public int Number { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public int Zip { get; set; }
    public string Place { get; set; }
    public string Country { get; set; }
}

public class CustomerDto
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string AddressStreet { get; set; }
    public int AddressZip { get; set; }
    public string AddressPlace { get; set; }
    public string NotMapped { get; set; }
}

[TestMethod]
public void MappingComplexObjects()
{
    Mapper.CreateMap<Customer, CustomerDto>()

    Address address = new Address() { Street = "Main", Country = "CH" };
    Customer customer = new Customer() { LastName = "Graber", Address = address };

    CustomerDto dto = Mapper.Map<Customer, CustomerDto>(customer);

    Assert.AreEqual("Graber", dto.LastName);
    Assert.AreEqual("Main", dto.AddressStreet);
    Assert.IsNull(dto.NotMapped);
}

Gefällt einem dies nicht kann man die Felder per opt.MapFrom wie schon erklärt aus einem beliebigen Feld (oder Wert) übernehmen.

 

Konfiguration überprüfen

Im vorherigen Beispiel wurde das Feld NotMapped nicht gesetzt. Da es im Ausgangsobjekt kein entsprechendes Feld gibt wird es von AutoMapper auch nicht gefüllt. Falls man dies als Fehler ansieht kann man die Konfiguration durch AutoMapper überprüfen lassen:

[TestMethod]
public void ValidateMapping()
{
    Mapper.CreateMap<Customer, CustomerDto>();
    Mapper.AssertConfigurationIsValid();
}

Durch das nicht vorhandene Feld NotMapped wird man beim Ausführen diese Fehlermeldung erhalten:

Test method TestProject1.UnitTest1.ValidateMapping threw exception:
AutoMapper.AutoMapperConfigurationException:
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the
source/destination type

 

Wohin mit der Konfiguration?

Es genügt AutoMapper beim Start der Applikation über die Methode Mapper.CreateMap() zu konfigurieren. Je nach Anwendungstyp kann man dies einmalig in der Main-Methode oder in der Datei Global.asax machen. So wird der notwendige Code für AutoMapper gegenüber den hier gezeigten Beispielen noch einmal kleiner.

 

Fazit

Mit AutoMapper hat man ein Werkzeug zur Verfügung mit dem man nicht mehr selber den ganz banalen Mapping-Code schreiben muss. Wird es komplexer bietet einem AutoMapper eine Vielzahl von Einstellungsmöglichkeiten. Allerdings gilt es wie bei jedem Werkzeug genau zu prüfen ob und in welchem Umfang der Einsatz sinnvoll ist.

Kategorien:.Net, webDotNet Schlagworte:
Follow

Bekomme jeden neuen Artikel in deinen Posteingang.

Schließe dich 175 Followern an