Unique Software

Blog

News und Trends

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.

maxRequestLength vs. maxAllowedContentLength

Wer sich mit Dateiuploads beschäftigt wird sich früher oder später Gedanken über Dateigrößenbeschränkungen machen wollen oder müssen.

Die Einstellung dafür findet sich in der web.config. Jedoch gibt es dabei gewisse Dinge zu beachten:

  1. Die MSDN ist sehr spärlich mit Informationen zu den Stellen an denen Änderungen notwendig sind und den vorhandenen Abhängigkeiten.
  2. Je nach verwendeter IIS-Version sind unterschiedliche Werte anzupassen.

Konfiguration des IIS

Relevant ist das Attribut maxAllowedContentLength im Element system.webServer / security / requestFiltering / requestLimits. Zu beachten ist hier, dass dieser Wert in Byte ist. Für Dateigrößen von 20 MB ist hier daher 20971520 einzutragen.

Konfiguration der ASP.NET Runtime

Relevant ist das Attribut maxRequestLength im Element system.web / httpRuntime. Zu beachten ist, dass dieser Wert in Kilobyte ist. Für Dateigrößen von 20 MB ist hier daher 20480 einzutragen. Wird der IIS 6 verwendet, spielt maxAllowedContentLength keine Rolle und es muss nur maxRequestLength angepasst werden.

 

Entwickler erobern Leipzig

Jedes Jahr im Oktober gibt es in Leipzig eine Invasion von Entwicklern. Was als Event für .NET Entwickler begann wurde dieses Jahr konzeptionell etwas erweitert und hat nun den Namen Developer OpenSpace. So richtig hat sich mir die Notwendigkeit dieser Änderung noch nicht erschlossen, schließlich war es auch bisher schon so, dass sich immer auch Sessions zu eher .NET-fremden Themen oder sagen wir mal besser Randthemen aus dem Blickwinkel eines .NET Entwicklers gefunden haben. Das ist auch ganz gut - ergibt sich so doch der ein oder andere Blick über den Tellerrand. Und es schadet auf keinen Fall, mal was von Java oder Ruby gesehen zu haben. Ich persönlich sehe dieses Wochenende immer wieder als gute Gelegenheit für einen Austausch über Erfahrungen oder um neue Ideen oder Denkanstöße zu bekommen. Mehr...

In die JSON-Serialisierung eingreifen

Der Anwendungsfall

In einer Seite sollen Diagramme angezeigt werden. Für die Darstellung habe ich mich für flot entschieden. Dabei handelt es sich um eine JavaScript-Bibliothek, die in einem Platzhalter mit Hilfe von Canvas-Elementen Charts in diversen Formaten zeichnen kann. 

Im ersten Beispiel soll ein Tortendiagramm erzeugt werden. 

Die Datenstruktur ist dabei recht simpel. Es handelt sich um ein Array von Objekten mit jeweils einem Label und einem Zahlenwert für die Daten.

var pieData = [{ label: "geschieden", data: 5 }, { label: "verheiratet", data: 25 }, { label: "ledig", data: 30 }];
$.plot($("#myChart"), pieData, {
    series: {
        pie: {
            show: true
        }
    },
    grid: {
        hoverable: true
    },
    legend: {
        labelBoxBorderColor: "none"
    }
});

Im zweiten Beispiel soll ein Liniendiagramm erzeugt werden, das Werte mehrerer Serien über einen Zeitraum darstellen kann.

Die Datenstruktur ist ähnlich wie die des Tortendiagramms. Nur nun enthält data nicht mehr einen einzelnen Wert, sondern ein Array von x-y-Werten. das Beispiel beinhaltet die Daten vom 01.11. bis 03.11.2012. Die x-Achse ist auf den Zeitraum 31.10. bis 04.11. arretiert, damit der erste Datenwert nicht direkt am Rand des Charts liegt.

var lineData = [
    { label: "aktive Kunden", data: [[1351724400000, 213], [1351810800000, 215], [1351897200000, 217]] },
    { label: "Support Tickets", data: [[1351724400000, 100], [1351810800000, 80], [1351897200000, 70]] }
];
$.plot($("#myChart"), lineData, {
    xaxis: {
        mode: "time",
        min: new Date(2012, 09, 31).getTime(),
        max: new Date(2012, 10, 4).getTime(),
    },
    yaxis: {
        tickDecimals: 0,
        min: 0,
        max: 300
    },
    series: {
        lines: { show: true },
        points: {
            radius: 3,
            show: true,
            fill: true
        }
    },
    grid: {
        hoverable: true
    },
    legend: {
        labelBoxBorderColor: "none"
    }
});

So weit so gut. Mehr...

Als Sprecher bei der .NET Usergroup Dresden

Im Grunde war es ein Heimspiel. Beim letzten Treffen der .NET Usergroup Dresden vor gut einer Woche war ich dort mal wieder zur Abwechslung als Sprecher.

Thematisch ging es dabei eher um ein Randgebiet für .NET Entwickler. Gemeinsam mit Matthias Wendt widmeten wir den Abend dem SQL Server 2012. Während Matthias das Thema Datenqualität und die in dieser Version neu hinzugekommenen Data Quality Services näher beleuchtete und anhand von Beispielen erklärte, ging ich auf Neuerungen in TSQL ein und zeigte anhand von Vorher-Nachher-Statements, ob und wo sich hier Vereinfachungen ergeben.

Es war ein sehr spannender Abend und anhand der doch recht großen Teilnehmerzahl von über 15 die auch den Abend mit aktivem Mitmachen und Rückfragen bereichert haben war eindeutig erkennbar, dass es auch noch .NET-Entwickler gibt, die sich um Datenspeicherung kümmern und nicht nur im Frontend unterwegs sind.

Englische Version Englische Version

IIS Express komfortabel konfigurieren

... oder "Ich hab da mal was vorbereitet".

Wer schon einmal versucht hat, seinen IIS Express mit SSL mit einem abweichenden Hostnamen (also nicht localhost oder der tatsächliche Rechnername) laufen zu lassen wird es kennen - mit nur sieben winzigen Schritten kommt man zum Erfolg:

  1. hosts-Datei anpassen
  2. Bindings in der applicationhost.config des IIS Express anpassen
  3. mit netsh die Urls für gesicherte und ungesicherte Verbindungen in http.sys reservieren
  4. ggf. mit netsh die entsprechenden Ports an der Windows Firewall öffnen
  5. mit makecert selbstsigniertes Zertifikat erstellen
  6. in der Management-Konsole den Fingerabdruck des neuen Zertifikats suchen
  7. das erstellte Zertifikat mit netsh dem gewünschten SSL-Port zuweisen

Und da das RequireSSL-Attribut fest auf Port 443 verweist und man ggf. einen anderen Port verwendet, kann es sein, dass man noch eine URL-Rewrite-Rule in der web.config einrichten muss.

Die ganzen Schritte hat Scott Hanselmann sehr detailliert in seinem Post Working with SSL at Development Time is easier with IISExpress zusammengefasst.

Interessant ist der letzte Abschnitt des genannten Posts - denn dort zeigt er, dass es noch einen undokumentierten Weg gibt, der uns die meisten der genannten Schritte abnimmt. Mit Hilfe des Kommandozeilentools IISExpressAdminCmd können solche benutzerfreundlichen Urls in http.sys und hosts-Datei hinzugefügt und auch wieder entfernt werden - und das sowohl für ungesicherte als auch ssl-gesicherte Urls. Einzig um die Anpassung der applicationhost.config und ggf. notwendiger Url-Rewrite-Regeln kommt man auch damit nicht herum. 

Ein kleines Manko hat dieses Tool - es werden nur reine Rechnernamen akzeptiert (z.B. contoso); also die Konfiguration einer kompletten Url mit verschiedenen Levels (z.B. dev.contoso.com) ist damit nicht möglich. In diesem Fall kann man nicht die Abkürzung verwenden, sondern ist auf den langen Weg angewiesen.

Englische Version Englische Version