code it

Martins Tech Blog

REST-Services mit SOAPUI testen

Schon in Zeiten von SOAP-Webservices war SOAPUI ein gutes Tool für funktionale Tests der Schnittstelle. Besonders im .NET-Framework, das es dem Entwickler so einfach wie möglich macht, indem Proxies angelegt werden und gleich die große Deserialisierungsmaschinerie anspringt, ist es durchaus an einigen Stellen sinnvoll, überprüfen zu können was genau an Markup über die Leitung geschickt wird und wenn Kommunikation oder Deserialisierung fehlschlagen.

Auch bei rest-basierten Services kann das an vielen Stellen sinnvoll sein. In meinem aktuellen Beispiel verwende ich einen REST-Service eines Drittanbieters von einem Android-Phone aus. Leider ist der Service des Anbieters noch in der Entwicklung und die Schnittstelle ändert sich gelegentlich. In meinem Fall gab es ein Serialisierungsproblem auf Anbieterseite - so wurden Objekte an einem Endpunkt, der eine Liste zurückgeben sollte nicht immer als Objektliste serialisiert, was dann natürlich bei der Deserialisierung zu argen Problemen führt. Dafür habe ich mir mit SOAPUI einen Test geschrieben.

Gehen wir von folgendem Szenario aus: Es gibt einen Endpunkt, der JSON zurückgibt. Laut Schnittstellen-Definition handelt es sich dabei um eine Liste von Personendaten. Leider ist es bei der Implementierung zu einem Fehler gekommen so dass nicht immer eine Liste zurückgegeben wird. Ein entsprechendes fehlerhaftes Beispiel ist in .NET schnell erstellt.
public class SampleController : Controller
{
    public JsonResult GetAll()
    {
        var persons = new PersonRepository().GetAll();
        if (persons.Count == 1)
        {
            return this.Json(persons[0], JsonRequestBehavior.AllowGet);
        }

        return this.Json(persons, JsonRequestBehavior.AllowGet);
    }
}

Nun zum eigentlichen Punkt - der Test. Ein Projekt in SOAPUI ist schnell erstellt.

Basierend auf diesem Request kann nun mit Hilfe des entsprechenden Kontextmenü-Eintrags ein neuer Test erzeugt werden.


Nun müssen nur noch Assertations festgelegt werden. Das kann im entsprechenden Tab erledigt werden.
Meine erste Assertation ist, dass Statuscode 200 zurückkommt.

Basierend auf den Eingabeparametern (die es in meinem Beispiel nicht gibt) könnte man auch auf andere Statuscodes prüfen - z.B. 401 (Unauthorized) oder 409 (Conflict) usw.

Prüfung 2 ist, ob wir eine Liste zurückbekommen, die den Anforderungen entspricht. Das macht man am besten scriptgesteuert. SOAPUI greift dazu auf Groovy-Scripte zurück:

Ein Script könnte so aussehen:
import groovy.json.JsonSlurper 

def response = messageExchange.response.responseContent
def slurper = new JsonSlurper()
def json = slurper.parseText response

List persons = (List) json;
assert !(persons.isEmpty())
persons.each{
	assert it.LastName != null
	assert it.FirstName != null
}
So kann man nun feststellen, ob das Ergebnis stimmt oder eben nicht. Bekomme ich statt der erwarteten Liste nur ein Objekt zurück, schlägt hier der Cast fehl.

Diese Tests kann man nun einzeln oder im Kommandozeilen-Testrunner ausführen und so automatisiert feststellen, ob das Backend tut was es tun soll.

Rückblick auf das MobileCamp 2014 - der Sonntag

Tag 2
Auch der zweiten Tag begann mit einer Keynote und diese war besonders interessant und kurzweilig. Zwei Google Glass zum selber ausprobieren und ein Xiaomi zum ausprobieren der chinesischen Konkurrenz für westliche Mobiltelefonhersteller waren der perfekte Auftakt für den Tag. Und ganz besonders spannend: Den ganzen Tag lang konnten Interessierte die Hardware ausprobieren.

Im Anschluss daran widmete ich mich einer Session betitelt mit "Meetings verbessern" und es war interessant herauszufinden wie andere mit Fokussierungsproblemen in Meetings umgehen, denn wer kennt sie nicht ergebnislose Meetings oder Marathonmeetings.

Und nun: ein Mittagessen zugeschnitten auf Entwickler: Pizza und Mate. Der schiefe Turm von Pizza(schachteln) hat es übrigens nach dem Foto nicht mehr lange ausgehalten.

Nach dem Mittag wieder ganz spannend für mich das Thema Open Source Compliance. Wie verhindere ich Copyleft-Effekte im Business Umfeld, welche Lizenzen sind verwendbar, wenn man Business-Anwendungen schreibt, die nicht OpenSource sein dürfen. Es gab viele Tipps, wie man gut durch den Lizenzdschungel kommt und mit vielen praktischen Tipps aus dem juritischen Alltag.

Die letzte themenbezogene Session war für mich Crowdfunding für mobile Apps und hat für mich etwas Licht ins Dickicht gebracht. Dachte ich bisher immer an Crowdinvesting und was es dabei alles zu beachten gibt, so bietet Crowdfunding eine ganz andere Perspektive. Und ganz wichtig dabei auch das Herangehen an so einen Funding-Prozess aus Unternehmenssicht. Es war gut, dass so viele dabei waren, die direkt aus der Praxis mitreden konnten, weil sie den Prozess bei Unternehmen schon begleitet haben und wussten was genau relevante Punkte sind.

Für alle, die sich etwas näher mit einem der Themen an denen ich teilgenommen hab oder auch an anderen beschäftigen wollen: unter http://lanyrd.com/cxdcb findet sich ein Großteil der Präsentationen und Unterlagen, die Grundlage für die Sessions waren.

Zu vielen Zeitpunkten wäre ich gern in mehreren Sessions parallel gewesen, einfach weil es so interessante Themen gab.

Ich kann diese Konferenz einfach nur jedem empfehlen, der auch nur im entferntesten etwas mit Mobile zu tun hat.

Noch einmal vielen Dank und im nächsten Jahr bin ich gern wieder mit dabei.

Rückblick auf das MobileCamp 2014 - der Samstag

Ein spannendes Wochenende geht vorbei und nach einiger Abstinenz vom Bloggen möchte ich genau das zum Anlass für einen Blogpost nehmen. Auch wenn im Vorfeld viele Teilnehmer unterschiedliche Angaben dazu gemacht haben - ja, es ist inzwischen schon das 6. MobileCamp, wie man dann unschwer am Tshirt erkennen konnte. Und mit einem Besucherrekord von knapp 300 Teilnehmern von denen überraschenderweise noch immer die Mehrzahl direkt aus Dresden und Ostsachsen kam, konnten Maßstäbe gesetzt werden. 

Thematisch richtet sich dieses Barcamp sowohl an Entwickler als auch an Designer, Grafiker, Rechtsexperten, Projektmanager, Vertriebler - eben alle, die sich mit der Thematik Mobile auseinandersetzen. Trotzdem war der Anteil an Nicht-Entwicklern relativ gering.

Für mich war es das dritte Mal, dass ich beim MobileCamp dabei war und was soll ich sagen: es hat sich gelohnt. An dieser Stelle vielen Dank an die Veranstalter und die anderen Sponsoren die die Veranstaltung, die das Barcamp erst möglich machen. Und wer sich wegen der Formulierung fragt: Ja,dieses Jahr waren wir mit unter den Sponsoren.

Nun aber zum spannenden Teil....

Tag 1
Der Tag beginnt mit einer großen Vorstellungsrunde (wer bin ich, was mache ich und warum bin ich hier), was bei der Anzahl der Teilnehmer schon mal eine ganze Weile in Anspruch nimmt. Im Anschluss daran - wie bei jedem Barcamp - Sessionfindung und Raumplanung. Ganz interessant - dieses Jahr gab es sowohl am ersten als auch am zweiten Tag eine Keynote, was eigentlich barcampunüblich ist. 

Die Keynote am ersten Tag drehte sich rund um das Thema Firefox OS. Und viele Aspekte waren doch sehr bekannt von anderen Plattformen, denn alles ist eine App. Sehr beruhigend ist, dass die Mozilla-Entwicklergemeinde wohl aus den Fehlern anderer Hersteller gelernt haben und an "Features" wie Markieren und Copy&Paste schon in der ersten Version denken.

In der zweiten Session des Tages drehte es sich für mich rund um das Thema Gamification und es war für mich sehr spannend einen Einblick in die wissenschaftlichen Hintergründe zu bekommen und das auf einem gut verständlichen und High-Level Weg. 

Nach der Mittagspause in der es (typisch ostdeutsch) Soljanka aus der Gulaschkanone gab

Im Anschluss daran stand ich das erste Mal vor der Qual der Wahl: Unity und Game Erstellung oder App Marketing. Als jemand mit BWL-Herz, landete ich in der App-Marketing Session die anhand eines aktuellen Beispiels und damit natürlich auch mit etwas Eigenmarketing der Session-Ownerin sehr interessante Aspekte aufzeigte.

Im Anschluss daran schaffte es Torsten mit einer Session zum Thema Psychologie die Hälfte der Teilnehmer in seinen Bann zu ziehen. Da ich vom  letzten den Developer Open Space aber schon einen Eindruck gewinnen konnte was er da erzählen wird, zog es mich eher zu einer Session die sich thematisch mit rechtlichen Neuerungen im eCommerce beschäftigt. Auch wenn ich aktuell noch keinen Onlineshop betreue und es mich deswegen nur am Rande betrifft, war es doch sehr spannend, zu diskutieren, was da ab Mitte Juni ansteht und wie Shopbetreiber damit umgehen müssen.

Die vorletzte Session des Tages war für mich zwar interessant, aber ohne direkte Anwendungsmöglichkeit: Haitech - wie steuere ich die Fernbedienung eines Spielzeugs fern, um schlechtes UX des Spieleherstellers zu umgehen. Es war spannend, was man mit ein paar Transistoren und Widerständen und ein klein wenig Programmierung erreichen kann, aber ich habe gemerkt dass ich bisher doch zu selten einen Lötkolben in der Hand hatte als dass ich das direkt machen würde. Glücklicherweise sind genug Ingenieure in meinem Bekanntenkreis.

17 Uhr - die letzte Session des Tages beginnt. Für mich Gamification Teil 2 - dieses mal ein Deep Dive in die wissenschaftlichen Ansätze - sehr sehr spannend, jedoch in Anbetracht der Uhrzeit hatte ich doch gelegentlich Schwierigkeiten, dem Ganzen mit "hier ist noch eine Grafik, die zeigt folgendes" und "ich hab hier eine Tabelle in der wird dargestellt, dass ... " zu folgen.

Den krönenden Abschluss des Tages gab es wie jedes Jahr im Citybeach Dresden und auch wie jedes Jahr bei Regen - Traditionen soll man beibehalten.

jqGrid und "unrecognized expression # tbody:first"

In einem Projekt habe ich das jQuery-Plugin jqGrid eingesetzt, um Daten tabellarisch darzustellen. Allerdings überraschte mich das jqGrid beim Versuch, die Zeilen nach einer Spalte zu sortieren damit, dass sämtliche per JavaScript hinzugefügten Zeilen wieder entfernt wurden und sich ansonsten nicht viel tat.

Ein kurzer Blick in die Konsole zeigte, dass bei der Aktion ein Fehler geworfen wurde: unrecognized expression # tbody:first irgendwo in den Tiefen von jQuery.

Dass jQuery selbst mit hoher Wahrscheinlichkeit nicht das Problem sein kann, zeigt die Erfahrung.

Problem ist folgendes: Da ich mehrere dieser Grids auf einer Seite verwende udn diese auch noch dynamisch erzeugt werden, habe ich darauf verzichtet, meinen zugrunde liegenden Table-Elementen eine Id zu verpassen. Das Plugin aber benötigt sowohl für die Tabelle selbst als auch für die Zeilen jeweils Ids. Häufig kann man im Plugin-JavaScript Aktionen wie diese hier finden:

$("#"+$.jgrid.jqID(ts.p.id)+" tbody:first")

für den Zugriff auf die Tabelle und

$("#"+$.jgrid.jqID(t.p.id)+" tbody:first tr#"+$.jgrid.jqID(sr))

für den Zugriff auf gewisse Zeilen.

Lösung ist also, sich für jede Tabelle eine nach Möglichkeit eindeutige Id auszudenken und diese dann zu setzen.

Sei nett zu deinem DBA...

... und setz den Application Name im ConnectionString.

Wer schon einmal in die Verlegenheit kam, und prüfen musste, warum es auf einer Datenbank zu Fehlern kommt und welche Anwendung diese erzeugt, der wird froh sein, wenn der Application Name gesetzt war.

Worum geht es?

Beim Verbindungsaufbau zum SQL Server wird nicht nur Benutzername und Kennwort, sondern auch ein Anwendungsname ausgetauscht. Dieser Anwendungsname wird in Tracing-Tools (wie z.B. dem Profiler) auch angezeigt.

Nun ist es für die Fehlersuche sehr sinnvoll, wenn dieser Anwendungsname eindeutig ist.

Leider wird in der Praxis häufig vergessen, diesen zu setzen, was dazu führt, dass hier nur der Standardwert .NET SQLClient Data Provider steht. Das ist für die Problemsuche nicht sehr hilfreich. Mit den neueren Projekt-Templates von Visual Studio, in denen Entity Framework verwendet wird, hat sich dieses Problem nur etwas verlagert. Hier ist der Parameter zwar schon im ConnectionString enthalten, wird aber auf den neuen Standardwert EntityFramework gesetzt - auch nicht sehr hilfreich.

Wie setzt man den ApplicationName?

Im ConnectionString gibt es den Parameter Application Name oder die gleichbedeutende Abkürzung App. Dieser muss gesetzt werden. 

Beispiele:

<connectionStrings>
    <add name="MyEntities" connectionString="metadata=res://*/Models.MyModel.csdl|res://*/Models.MyModel.ssdl|res://*/Models.MyModel.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=MyDb;integrated security=True;MultipleActiveResultSets=True;App=Meine Anwendung"" providerName="System.Data.EntityClient" />
</connectionStrings>
<connectionStrings>
    <add name="DefaultConnection" connectionString="Server=.;Database=MyDb;Integrated Security=SSPI;Application Name=Meine Anwendung;" providerName="System.Data.SqlClient" />
</connectionStrings>

Das geht sowohl in klassischen ConnectionStrings als auch in Connectionstrings für das Entity Framework.

SetWindowHookEx - cool oder nur Fingerübung?

Die Anforderung ist recht schnell erklärt: Erkenne, wann ein Fenster einer Anwendung maximiert, minimiert oder wiederhergestellt wird. "Das kann doch so schwer nicht sein" denkt man sich da, schließlich wirft Windows ja nur so mit Nachrichten um sich, die man einfach nur abfangen muss. Die Windows-API ist dein Freund. Ok, ganz so einfach ist es dann doch nicht, sonst bräuchte dieser Blogpost ja nicht geschrieben werden.

Damit das Fensterhandling und auch so ziemlich alles andere in Windows funktioniert, werden Nachrichten an Fenster gesendet. Zumeist macht Windows das selbst (z.B. Fenster 358: Maximiere dich"). Kommt diese Nachricht am Fenster an, gibt es dort eine Kette von "Abonnenten" - die hook chain. Und in diese Kette kann man eigene Funktionen eingliedern lassen, die dann Teil dieser Kette werden.

Mehr...

Goodbye MDI mit Excel 2013

Ich habe recht häufig den Fall, dass ich zwei Arbeitsblätter nebeneinander liegen haben musste, um diese zu vergleichen. In den letzten Versionen war es es so, dass beim Doppelklick auf eine Datei die mit Excel verknüpft war (*.xlsx, *.csv usw.) diese Datei brav geöffnet wurde, aber dummerweise immer in dem bereits bestehenden Excel-Hauptfenster. Da helfen mir auch die beiden Monitore und der erweiterte Desktop nicht viel. Besonders ärgerlich ist das, da ausnahmslos alle anderen Office-Programme sich hier genau wie erwartet verhielten und ein neues Hauptfenster öffneten.

Vor kurzen habe auch ich den Schritt gewagt und auf Office 2013 aktualisiert. Positiv überrascht war ich, als ich nun wieder genau den "Fehler" machte und einen Doppelklick auf eine Excel-Datei ausführte und mich seelisch schon darauf einstellte, wieder das bekannte Problem zu erleben... aber nein, es öffnete sich ein weiteres Excel-Fenster, welches ich frei positionieren konnte. Kleine Änderung, große Wirkung.

Clickjacking und was man dagegen tun kann

"Unsere neue Webanwendung ist anfällig für clickjacking" - nachdem ich diese Information bekam, musste ich zugegebenermaßen erstmal ganz scharf überlegen, was man mir damit sagen wollte.

Was steckt dahinter?
Lädt man eine fremde Seite in einem iframe, so kann man darüber transparente Steuerelemente legen. Der Benutzer denkt nun, er interagiert mit der eigentlichen Anwendung, klickt aber in Wahrheit auf die transparenten Elemente und löst so Aktionen aus, die er nicht auslösen möchte. Ein eher harmloses Beispiel dafür wäre ein transparenter Like-Button für eine fremde Facebookseite der z.B. über einem Google-Suchformular liegt und so statt der Suche erst einmal den Like auslöst.

Wie begegnet man nun diesem Problem?
Es gibt mehrere Ansätze, die man verfolgen kann. Eine in meinen Augen sehr gute Zusammenfassung dafür bietet dieser Blogpost. Erste Möglichkeit ist es, JavaScript zu verwenden und so dem Browser das Laden der Seite im iframe zu verbieten. Neuere Browser (lt. Wikipedia Internet Explorer ab 8.0, Firefox ab 3.6.9, Opera ab 10.50, Safari ab 4.0 und Chrome ab 4.1.249.1042) unterstützen zudem den X-Frame-Options-Header, den man in der Antwort mitsenden kann, um so die Darstellung im iframe zu unterbinden.

Eine Möglichkeit, dies in ASP.NET-Anwendungen zu verwirklichen findet man in diesem Artikel zum Thema Security. Und wenn man einmal dabei ist, an den Headern herumzuschrauben, kann man auch gleich noch einen Blick auf die anderen Header werfen, die automatisch hinzugefügt werden.

Field oder Property, das ist hier die Frage

Manchmal ergeben sich im persönlichen Gespräch Grundsatzdiskussionen über Programmierstile und Herangehensweisen und so ist es auch in diesem Beispiel, welches sich erst kürzlich zugetragen hat. Die Frage ist: Auto-Property oder öffentliches Feld - welcher Variante ist der Vorrang zu geben?

Möchte man Daten aus einer Klasse nach außen freigeben, so ist die einfachste Möglichkeit, einfach ein Feld zu deklarieren und diesem den Zugriffsmodifizierer public zu verpassen:

public class Person
{
    public string LastName;
    public string FirstName;
}

Diese Möglichkeit gibt es, Sie widerspricht aber dem Konzept der Kapselung. Datenzugriffe mit Eigenschaften zu kapseln bietet zum einen die Möglichkeit einen dedizierten Zugriff auf private Informationen des Objektes zu gewährleisten und vielleicht auch noch eine Validierung der Daten vorzunehmen, die dann gespeichert werden sollen. Im Standardfall sieht das Ganze so aus:

private string _name;
public string Name
{
    get { return _name; }
    set { _name = value; }
}

Damit gibt es ein privates Feld, das über die Eigenschaft nach außen verfügbar gemacht wird und im Setter können dann Prüfungen durchgeführt werden.

Seit C# 3.0 gibt es nun die Möglichkeit, autoimplemented Properties zu verwenden:

public string Name { get; set; }

Damit ist noch immer eine Eigenschaft vorhanden, jedoch ist die Anlage des sogenannten Backing Fields damit nicht mehr notwendig - das übernimmt der Compiler. Was damit auch entfällt, ist die Möglichkeit zusätzliche Prüfungen im Setter hinzuzufügen.

Dieser Logik folgend, stellt sich nun aber die Frage: Warum sollte ich autoimplemented Properties verwenden und nicht public Fields (wie im ersten Beispiel). Die eben genannten offensichtlichen Vorteile der Eigenschaften entfallen bei autoimplemented Properties ja.

Grund 1: Asymmetrische Sichtbarkeit 

Eigenschaften erlauben die Definition asymmetrischer Sichtbarkeit von Getter und Setter:

public string Name { get; private set; }
public string DateOfBirth { private get; set; }

Ein Feld ist immer komplett public oder komplett private, nicht aber private beschreibbar und öffentlich schreibgeschützt.

Grund 2: Definition in Interfaces

Eigenschaften können in Interfaces festgeschrieben werden, während das für Felder nicht möglich ist.

public interface IPerson
{
    string LastName { get; set; }
    string FirstName { get; set; }
}

public class Student : IPerson
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

Bei der Verwendung von Feldern kann man nicht sicherstellen, dass alle Objekte vom Typ Student über öffentlich verfügbare Felder für Nachname und Vorname verfügen.

Grund 3: Überschreibbarkeit

Felder können nicht überschrieben werden. Während man bei Eigenschaften problemlos in Basisklassen eine Deklaration mit virtual oder abstract vornehmen kann, um sicherzustellen, dass ein bestimmter Wert immer vorhanden ist, und die Initialisierung dann ggf. aber doch an eine spezialisiertere Klasse zu delegieren, so ist das mit Feldern nicht möglich.

Grund 4: Abwärtskompatibilität

"Dieser Code wird sich nie ändern" gibt es nicht und auch an der noch so undenkbaren Stelle wird irgendwann einmal der Zeitpunkt gekommen sein, an dem irgendeine Änderung notwendig ist. Und dann ist es gut gewappnet zu sein und eben nicht auf das Feld angewiesen zu sein, sondern die Auto-Property vielleicht aufzubrechen und hier noch zusätzliche Dinge zu machen. Der große Vorteil dann: Die Schnittstelle nach außen muss sich vielleicht nicht zwingend ändern und bereits bestehender Code der die Komponente verwendet, kann in gleicher Art und Weise weiter laufen ohne breaking changes.

Grund 5: Data Binding

Möchte man früher oder später die Objekte zur Datenbindung in WPF verwenden, so benötigt man Properties. Klar ist in diesem Fall keine Änderungsbenachrichtigung möglich - es sei denn man verwendet Aspekte, aber verwendbar sind sie so schon.

Wahrscheinlich gibt es noch den ein oder anderen weiteren Grund. Ich denke, die obige Liste bietet noch Platz für Erweiterungen.

HTTP-Status 400 trotz Inhalt

Der Anwendungsfall: Eine ajax-basierte Anwendung soll im Fehlerfall in den Ajax-Requests zwar einen Inhalt zurückgeben, der zu rendern ist, gleichzeitig aber auch einen von 200 abweichenden Statuscode, damit im Browser z.B. im JavaScript eine Unterscheidung stattfinden kann. Verkürzt und stark vereinfacht sieht das dann aus wie im folgenden Beispiel:

[HttpPost]
public ActionResult BuySomething(BuyProduct model)
{
    if (!ModelState.IsValid)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return this.PartialView(model);
    }

    return this.PartialView("SuccessView", model);
}

Damit kann der Client nun im Fehlerfall zusätzliche Aktionen durchführen.

Im IIS7 funktioniert das out-of-the-box leider nicht, da hier mit Standardeinstellungen der Body-Content in der Antwort ersetzt wird. Um dieses Verhalten anzupassen, gibt es das Attribut existingResponse im Element system.webServer / httpErrors.

<system.webServer>
  <httpErrors existingResponse="PassThrough"></httpErrors>
</system.webServer>

Setzt man den Wert auf PassThrough, ersetzt der IIS den Content nicht, wenn gleichzeitig ein Statuscode >= 400 gesetzt wird.