Tag Archives: CSharp

dynamic^2 oder ”variable Variablen”

(Irgendwie mag Windows Live Writer kein ² in der Überschrift…) Erzürnt

Seit .NET 4 gehört C# (und natürlich VB.Net) zu dem Kreis der dynamisch typisierten Sprachen. Dies ermöglicht die DLR, die Dynamic Language Runtime.
D.h. man kann Variablen “spät binden” (late binding), d.h. sie werden erst zur Laufzeit in ihren konkreten Typ materialisiert.
Das erlaubt einem eine hohe Flexibilität für verschiedenste Szenarien, wie z.B. beim COM Interop, der Kommunikation mit anderen dynamischen Sprachen für .NET (IronPython, IronRuby, IronJS, Phalanger, …) oder einfach in Situationen in denen der konkrete Typ erst zur Laufzeit bekannt ist (Reflection, XML, …).

Ich möchte jetzt nicht weiter auf die Grundlagen eingehen, da es inzwischen genügend Dokumentation dazu gibt. Einfach mal in die MSDN Doku reinschauen.

Basierend auf dem Beispiel aus der Doku mit dem DynamicDictionary möchte ich auf eine kleine Erweiterung eingehen: variable Variablen.
PHP Programmierer wissen vielleicht was ich meine. In PHP ist es beispielsweise möglich folgendes zu schreiben:

$variableName = "age";
$obj = new stdClass();
$obj->{$variableName} = "31";

echo $obj->age;

Also die Variable (bzw. den Member) variabel zu halten.

In C# ist das Out of the Box nicht möglich. Durch zwei Erweiterungsmethoden kann diese “dynamische Dynamik” aber leicht nachgereicht werden:

public static object GetMember(this object obj, string memberName)
{
    var binder = Binder.GetMember(
        CSharpBinderFlags.None, memberName, obj.GetType(),
        new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
    var getterSite = CallSite<Func<CallSite, object, object>>.Create(binder);
    return getterSite.Target(getterSite, obj);
}

public static void SetMember(this object obj, string memberName, object value)
{
    var binder = Binder.SetMember(CSharpBinderFlags.None, memberName, obj.GetType(),
        new CSharpArgumentInfo[] {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null)
        });
    var setterSite = CallSite<Func<CallSite, object, object, object>>.Create(binder);
    setterSite.Target.Invoke(setterSite, obj, value);
}

Somit ist es auch in C# möglich folgendes zu schreiben:

string variableName = "Age";
dynamic obj = new DynamicDictionary();
((object)obj).SetMember(variableName, 31);

Console.WriteLine(obj.Age);

Das Unboxing mittels ((object)obj).SetMember/GetMember… ist dabei notwendig, da es sich um eine Erweiterungsmethode handelt und diese für dynamische Objekte nicht aufgelöst werden.

Alternativ könnte man auch schreiben:

DynamicObjectExtensions.SetMember(
obj, variableName, 31);

Interessant ist, dass die beiden Befehle komplett unterschiedlichen IL Code generieren. Wo bei ersterem Befehl der Methodenaufruf SetMember steht, wird bei zweiterem Befehl SetMember wiederum dynamisch aufgerufen, was einen kleinen Performanceoverhead bedeutet. Man kann diesen jedoch wieder verschwinden lassen, indem man einfach obj nach object castet:

DynamicObjectExtensions.SetMember(
(
object)obj, variableName, 31);
Advertisements
Tagged , , ,

Digest Authentifizierung für System.Net.Http.HttpClient

Wer’s brauch kann sichs hier herunterladen, oder noch besser, weiterentwickeln:

https://bitbucket.org/toburger/digestauthmessagehandler/

Voraussetzung ist das .NET Framework 4.5, da ich stark von den neuen async-Features gebrauch mache. Mit etwas TPL gebastel bekommt man es aber auch auf .NET 4 zum Laufen.

Die Inspiration für die Implementierung habe ich mir von hier geholt: http://blogs.msdn.com/b/henrikn/archive/2012/02/16/extending-httpclient-with-oauth-to-access-twitter.aspx

Features:

  • Authentifizierung mittels Digest
  • Zwischenspeichern des Credential Tickets, sodass bei jedem weiteren Request nicht ein neues Ticket erstellt werden muss (was jeweils zwei Requests zur Folge hätte)
  • Falls das Ticket verfallen ist, wird automatisch ein neues Ticket erstellt
Tagged , , , ,

Zusammengesetzte Eigenschaften mal anders

Kürzlich wurde ich gefragt wie ich folgende Aufgabe lösen würde:

Ich habe eine Personenklasse, welche Vorname, Nachname, Titel, usw. als Eigenschaften enthält und es soll anschließend eine Eigenschaft erstellt werden, welche diese Eigenschaften als String ausgibt.

Das Ganze soll natürlich so gelöst sein, dass, wenn eine der Eigenschaften leer ist keine überflüssigen Leerzeichen ausgegeben werden.

Der naive Ansatz wäre natürlich der gewesen:

return string.Format("{0} {1} {2} {3}",
    Title, FirstName, MiddleName, LastName);
nur bleiben mit dieser Implementierung eben genau die überflüssigen Leerzeichen stehen, wenn eine der Eigenschaften leer ist.

Dies könnte man lösen, indem man Replace und Trim des String-Objektes verwendet oder etwas Regex-Magie anwenden würde. Ich persönlich finde solche String Manipulationen aber nicht sonderlich elegant.

Andere Ansätze würden eine erquickliche Anzahl an if-Abfragen beinhalten und man müsste darauf achten dass die Leerzeichen an den richtigen Stellen eingefügt werden. Wartbar ist das Ganze auch nur bedingt.

Meine Implementierung würde so aussehen:

public string FullName
{
    get
    {
        var elements = new string[] { Title, FirstName, MiddleName, LastName };
        return string.Join(" ", elements
            .Where(e => !string.IsNullOrWhiteSpace(e)));
    }
}

Das elements-Array beinhaltet die Strings in der Reihenfolge wie sie ausgegeben werden sollen.
Der Join mit der LINQ-Abfrage sorgt dafür, dass nur die Elemente, welche nicht leer sind oder keine Leerzeichen beinhalten, ausgewählt werden und „vereint“ diese mit einem Leerzeichen getrennt.


Kommt nun eine weitere Eigenschaft hinzu, kann man diese einfach in das elements-Array an der gewünschten Position einfügen.

Tagged ,

Atomare farbige Konsolenausgabe (thread safe)

Ich hätte mir nicht gedacht, dass ich mal über so etwas triviales wie die Konsolenausgabe posten werde, aber wieso nicht, fange ich mit etwas an, was in jedem “Hello World!”-Beispiel zu finden ist und reichere es mit einem – hoffentlich – wissenswerten Tipp zum Thema Threading an… 😉

In einem meiner vielen Mockup-Projekte, in welchen ich einfach naiv drauf los programmiere um zu Lernen (jaja, so was mach ich ständig, nennt sich auch “trial and failure” oder “learning by doing”), bin ich auf folgendes Problem gestoßen:

Ich habe in meinem Programm, welches mehrere Threads instanziiert, in den einzelnen Threads Meldungen ausgegeben, was denn gerade passiert.

Nun ist das ja an sich nichts ungewöhnliches, WriteLine ist „thread safe“ und kann ohne Bedenken in mehreren parallel laufenden Threads verwendet werden, ohne dass sich die Threads in die Quere kommen.

Um in meinem Testprogramm nun Fehler besser von den „normalen“ Meldungen zu unterscheiden, habe ich diese rot eingefärbt.

Um die Konsolenausgabe einzufärben und anschließend in den Ursprungszustand wiederherzustellen ist folgender Code vonnöten:

Console.ForegroundColor = consoleColor;
Console.WriteLine("Meldung");
Console.ResetColor();

Wieso hab ich denn ein Problem damit?

Das Ganze hat nun aber einen entscheidenden Haken: der Code ist nicht atomar, das heißt, wird dieser Code von zwei Threads gleichzeitig aufgerufen, dann kann es sein, dass die Ausgabe die falsche Farbe hat!
Am besten ich erkläre es an einem Beispiel.
Folgender Code führt parallel eine Konsolenausgabe aus und weist ihr eine zufällige Farbe zu:

Random rnd = new Random();
Parallel.For(0, Console.WindowHeight - 1, i =>
{
    ConsoleColor consoleColor = (ConsoleColor)rnd.Next(7, 16);

    Console.ForegroundColor = consoleColor;
    Console.WriteLine("Meldung: {0}", consoleColor);
    Console.ResetColor();
});

Das Ergebnis kann man hier bewundern. Wie man sieht stimmen die Farben überhaupt nicht zusammen!

Die Lösung

Was man nun machen muss ist das Ganze atomar zu machen, also alle Threads während dieser Operation zu blockieren, bis die Ausgabe erledigt wurde.

Dies kann in C# mit einem Monitor.Enter oder mit dem C# Schlüsselwort lock (ist nichts anderes als ein Alias auf Monitor.Enter) erledigt werden:

lock (Console.Out)
{
    Console.ForegroundColor = consoleColor;
    Console.WriteLine("Meldung: {0}", consoleColor);
    Console.ResetColor();
}

Alles was innerhalb dieses locks passiert ist atomar, dh. keine anderen Konsolenoperationen kommen meinem Code in der Zwischenzeit in die Quere.

Tagged , ,

Notiz an mich: ‘throw’ ist gut, ‘throw ex’ ist böse

Richtig:

catch (FooException ex)
{
    // mach hier dein Ding
    throw;
}

Falsch:

catch (FooException ex)
{
    // mach hier dein Ding
    throw ex;
}

throw ex ist ein Fehler der von C#-Entwicklern gerne gemacht wird (vor allem von den Programmieren mit Java-Hintergrund), bzw. den man des Öfteren in Beispielen und Foren findet.

Der Unterschied ist, dass bei throw ex im Gegensatz zu throw der StackTrace verloren geht, was eigentlich NIE gewünscht ist.

Tagged , , ,

Wie kann ich prüfen, ob ein Benutzer Mitglied einer Gruppe im Active Directory ist?

Wem es so ergangen ist wie mir und gedacht hat, ist doch ganz einfach:
Ich instanziere ein neues System.DirectoryServices.AccountManagement.UserPrincipal und prüfe mit der Methode IsMemberOf, ob der Benutzer ein Mitglied der Gruppe ist, der täuscht sich!

Was zunächst relativ trivial erscheint, entpuppt sich als relativ verzwickt, wenn man mit Untergruppen arbeitet, denn dann gibt die Methode false zurück, obwohl man Mitglied einer solchen Gruppe ist.

Und genau das ist auch das Verzwickte daran, denn es wird klappen, wenn man nach der Gruppe prüft, welche direkt dem Benutzer zugewiesen wurde, jedoch das Prüfen auf Mitgliedschaft einer “Gruppe einer Gruppe” wird ein falsches Ergebnis zurückgeben, nämlich immer false.

Anbei ein Beispiel, wie so eine Hierarchie in der Praxis aussehen könnte:

Gruppe “Alle Benutzer von Firma …”

Gruppe “Alle Benutzer der Abteilung …”

Gruppe “Alle Benutzer der Abteilung … am Standort …

Benutzer “Hans Mustermann”

Ruft man nun

string userName = "HMustermann";         // Benutzer "Hans Mustermann"
string groupName = "MusterfirmaAlle";    // Gruppe "Alle Benutzer von Firma ..."

var pc = new PrincipalContext(ContextType.Domain);
var adUser = UserPrincipal.FindByIdentity(pc, userName);
var adGroup = GroupPrincipal.FindByIdentity(pc, groupName);

bool isMember = adUser.IsMemberOf(adGroup);

auf, wird man überrascht feststellen, dass isMember false ist.

Was man nun also tun muss ist die Untergruppen durchtraversieren und jeweils überprüfen, ob der Benutzer Mitglied dieser Gruppe ist.

Dies kann mit folgendem Code einfach erreicht werden:

private static IEnumerable<GroupPrincipal> GetGroupPrincipalsRecursive(
    GroupPrincipal groupPrincipal)
{
    yield return groupPrincipal;
    foreach (var subGroup in groupPrincipal.GetMembers()
        .OfType<GroupPrincipal>())
    {
        foreach (var subSubGroup in GetGroupPrincipalsRecursive(subGroup))
            yield return subSubGroup;
    }
}

Nun kann man folgendermaßen überprüfen ob es sich um ein gültiges Mitglied handelt:

bool isMember = GetGroupPrincipalsRecursive(adGroup)
    .Any(g => adUser.IsMemberOf(g));

Extension-Method

Da ich Erweiterungsmethoden liebe, hier ein weiteres Beispiel einer Implementierung:

static class UserPrincipalExt
{
    public static bool IsMemberOfRecursive(this UserPrincipal user, GroupPrincipal group)
    {
        return GetGroupPrincipalsRecursive(group)
            .Any(g =>
            {
                try { return user.IsMemberOf(g); }
                catch (PrincipalOperationException) { return false; }
            });
    }

    private static IEnumerable<GroupPrincipal> GetGroupPrincipalsRecursive(
        GroupPrincipal groupPrincipal)
    {
        yield return groupPrincipal;
        foreach (var subGroup in groupPrincipal.GetMembers()
            .OfType<GroupPrincipal>())
        {
            foreach (var subSubGroup in GetGroupPrincipalsRecursive(subGroup))
                yield return subSubGroup;
        }
    }
}

Verwendung:

bool isMember = adUser.IsMemberOfRecursive(adGroup);
Tagged , ,