code it

Martins Tech Blog

HTTPS-Redirect - aber konfigurierbar bitte

Manchmal möchte man erzwingen, dass komplette Seiten oder Subdomains - oder um es anders zu formulieren: ganze ASP.NET Webanwendungen - nur per HTTPS erreichbar sind. Real-World-Beispiele gibt es zuhauf: Banking-Seiten, Shops usw.

Eine Möglichkeit ist es, das Ganze fix im Code zu verdrahten. In ASP.NET gibt es ein Filter-Attribut, das genau diesen Redirect vornimmt - das RequireHttpsAttribute. Dieses kann man einfach über die Controller oder Actions schreiben oder eben für den hier betrachteten Fall als globalen Filter definieren.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        // für die ganze Seite HTTPS erzwingen
        filters.Add(new RequireHttpsAttribute());
    }
}

Nun möchte man aber vielleicht nicht immer auf die HTTPS-Seite weiterleiten, sondern nur in bestimmten Fällen. Ich würde beispielsweise gern auf meiner Entwicklungsmaschine auf SSL und den Aufwand den man dafür betreiben muss verzichten. Und ich hätte es gern konfigurierbar. Eine andere Instanz der Anwendung braucht dieses strikte Verhalten vielleicht nicht.

Dafür gibt es auch was - nämlich die web.config. Unter dem Key system.webServer können Redirects definiert werden. Ein entsprechender Eintrag könnte beispielsweise wie folgt aussehen:
<system.webServer>
  <rewrite>
    <rules>
      <rule name="HTTP to HTTPS redirect" stopProcessing="true">
        <match url="^(.*)$"/>
        <conditions>
          <add input="{HTTPS}" pattern="^OFF$" ignoreCase="true" />
          <add input="{HTTP_HOST}" matchType="Pattern" pattern="^localhost(:\d+)?$" negate="true" />
          <add input="{HTTP_HOST}" matchType="Pattern" pattern="^127\.0\.0\.1(:\d+)?$" negate="true" />
        </conditions>
        <action type="Redirect" redirectType="Permanent" url="https://{HTTP_HOST}/{R:1}" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

Was wird hier gemacht? Wie der Name schon andeutet, wird ein permantener (also Statuscode 301) Redirect vorgenommen - allerdings mit ein paar Ausnahmen: Wenn der Host localhost oder 127.0.0.1 ggf. noch gefolgt von einem Port ist, wird auf den Redirect verzichtet, denn dann befinde ich mich entweder auf dem Webserver oder auf der Entwicklungsmaschine und greife darüber zu. Eigentlich ganz einfach - oder?

Raspberry Pi Tweety

Der Raspberry Pi rockt. Damit kann man ziemlich coole Sachen machen. Allerdings ist es besonders für Entwickler, die bisher eher auf der .NET-Plattform unterwegs sind eine kleine Überwindung - ist es doch nur eine Platine und es läuft kein Windows drauf.

Mit ein bisschen Einarbeitung alles kein Problem. Ich möchte kurz zeigen, dass man mit den richtigen Werkzeugen ziemlich nah an der gewohnten Umgebung und damit dann alles ganz einfach ist. Mein Raspberry soll seine aktuelle CPU-Temperatur per Tweet versenden - ok, zugegeben etwas nerdig ist das schon, aber was solls.

Inbetriebnahme
Im Grunde braucht es erst einmal nur einen Raspberry, eine SD-Karte und ein Netzwerkkabel. Das Installationspaket findet man auf der Raspberry-Website. Ich hab mich für Raspbian entschieden. Für die Installation des Betriebssystem-Images hat sich der Win32DiskImager bewährt. Im Anschluss daran einfach die SD-Karte in den Raspberry reinstecken und das Strom- und das Netzwerkkabel anschließen - schon bootet er. 

Die restliche Konfiguration findet auf dem Gerät selber statt. Dazu findet man zunächst die IP-Adresse heraus, die der Router dem neuen Familienmitglied gegeben hat und verbindet sich dann mittels Putty. Mit den Credentials pi/raspberry kann man sich dann verbinden.

Als allererstes sollte man sich hier der Konfiguration und Installation benötigter Komponenten widmen. Folgende Commands empfehlen sich daher:
sudo raspi-config
sudo apt-get update
sudo apt-get upgrade
Mit Hilfe des erstem Commands vergrößert man die Partition auf die Größe der SD-Karte und gibt seinem Nutzer ein neues Kennwort. Mit den anderen beiden Commands aktualisiert man die Pakete auf das aktuelle Patchlevel.

Vorbereitung für die Ausführung von .NET-Programmen
Debian ist Linux, und mit Hilfe von Mono können wir hier .NET Programme laufen lassen. Das hat den großen Vorteil, dass die Entwicklung ganz gut im Visual Studio stattfinden kann und die Assembly dann mit Hilfe der Mono-Runtime auf dem Pi ausgeführt wird. Die meisten Stichpunkte sind schon gefallen... wir brauchen ein paar Pakete:
 
sudo apt-get install mono-runtime
sudo apt-get install libmono-system-core4.0-cil
Damit wird die Mono-Runtime und System.Core und damit die LINQ-Unterstützung installiert.

Teil 1: Erstellen einer .NET Konsolen-Anwendung
Ja genau, das ist alles! Wir erstellen eine .NET Konsolenanwendung im Visual Studio. 
using System;

namespace UniqueSoftware.Raspberry.StatusTweeter
{
    class Program
    {
        static void Main(string[] args)
        {
            new Worker().Run();
        }
    }


    public class Worker
    {
        public void Run()
        {
            Console.WriteLine("Hello World");
            
        }

    }
}
Diese Anwendung können wir jetzt Kompilieren und auf unseren Pi kopieren. Wichtig dabei sind die exe-Datei und die config-Datei. Als Tool zum Kopieren verwende ich WinSCP.

Unser Programm kann jetzt schon im Putty ausgeführt werden. Dafür einfach
mono ./UniqueSoftware.StatusTweeter.exe
eingeben. Ganz klar steht nach Mono der Pfad zur hochgeladenen Assembly - also den ggf. anpassen.

Teil 2: Auslesen der Temperatur
Die CPU-Temperatur kann mit Hilfe des Commands
vcgencmd measure_temp
oder auch
cat sys/class/thermal/thermalzone*/temp
ausgelesen werden. Die zweite Lösung hat den Charme, dass hier einfach eine unformatierte Zahl geliefert wird, womit das Wegschneiden der Maßeinheit wegfällt, allerdings sind es Tausendstel-Grad-Celsius.

Was macht dieses Command? Es öffnet alle Dateien die den Namen temp haben und in den Ordnern thermal/thermalzone* liegen, wobei * ein Platzhalter ist. Um das Auflösen des Platzhalters kümmert sich die Shell. Aus diesem Grund können wir das so nicht verwenden - aber ist auch kein Problem - wir können ja mit Hilfe des .NET Frameworks alle Unterordner in thermal ermitteln und dann das gleiche tun.
public IList<float> DetermineCpuTemperatures()
{
    var folder = new DirectoryInfo("/sys/class/thermal/");
    var subFolders = folder.GetDirectories("thermal_zone*");
    var fileResults = subFolders.Select(subFolder => Path.Combine(subFolder.FullName, "temp"))
        .Select(File.ReadAllText)
        .ToList();

    var result = new List<float>();
    foreach (var fileResult in fileResults)
    {
        int temperature;
        if (!int.TryParse(fileResult, out temperature))
        {
            continue;
        }

        var temperatureInDegree = ((float)temperature) / 1000;
        result.Add(temperatureInDegree);
    }

    return result;
}

Teil 3: Tweet versenden
Zunächst wird eine Twitter-App benötigt, weil ein API-Key und ein Secret benötigt wird. Dazu meldet man ich im Twitter Developer Portal mit seinem Twitter-Account an und legt eine neue App an. Wichtig ist, dass man der App Lese- und Schreibberechtigungen gibt. Auf der API-Key Seite dort sind 4 Keys relevant: API-Key und -Secret sowie der Access-Token mit dem zugehörigen Secret.

Mit Hilfe von NuGet wird nun TweetSharp hinzugefügt. Es fehlen nun in unserem Programm noch 2 Funktionen - eine die den Text des Tweets erzeugt und eine die den Tweet absetzt.
public string BuildTweet(IList<float> temperatures)
{
    if (temperatures.Count == 1)
    {
        return string.Format("Hier ist der Pi und meine CPU-Temperatur ist {0:f2} °C.",
            temperatures[0]);
    }

    return string.Format("Hier ist der Pi und meine CPU-Temperaturen sind {0}.",
        temperatures.Select(x => string.Format("{0:f2} °C", x)));
}

public void SendTweet(string message)
{
    const string API_KEY = "ri8VPJluqJTFiOKqNg5lTZ0AA";
    const string API_SECRET = "EQrg5XeatwSzmMlnB296ukSPJUlWNwLXsaPDhVPjaRuoBG5px1";
    const string ACCESS_TOKEN = "2312268955-Y2wOLzCy2Iw5ctK20N4SqdSHK9Zs6VvlInZUmEm";
    const string ACCESS_TOKEN_SECRET = "2LTmy2JRkGmFqLxggthASmvwpi7SKxwiJoq772BaHY7TL";

    var twitterApp = new TwitterService(API_KEY, API_SECRET);
    twitterApp.AuthenticateWith(ACCESS_TOKEN, ACCESS_TOKEN_SECRET);

    var tweet = new SendTweetOptions();
    tweet.Status = message;

    var result = twitterApp.SendTweet(tweet);
    if (twitterApp.Response.InnerException != null)
    {
        throw twitterApp.Response.InnerException;
    }
}
Die Hauptmethode des Programms ändert sich damit dann wie folgt:
public void Run()
{
    try
    {
        var temperatures = DetermineCpuTemperatures();
        var tweetText = BuildTweet(temperatures);
        SendTweet(tweetText);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
}
Das war's auch schon fast. Im Windows läuft das Programm schon. Im Mono läuft es im Standard erst einmal nicht, weil noch keine vertrauenswürdigen Zertifikate vorhanden sind. Das ändert man, indem man auf dem Pi  die Zertifikate von Mozilla importiert.
sudo mozroots --import --ask-remove
Sollte das nicht ausreichend sein, so kann man das komplette Mono Development Paket installieren und im Anschluss dem Zertifikatsmanager die Twitter-Seite hinzufügen.
sudo apt-get install mono-devel
sudo certmgr -ssl https://api.twitter.com
Ab sofort werden bei jedem Programmstart die CPU-Temperaturen an eure Follower geschickt. 

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.