Lazy Proxies mit Reflection.Emit

Man kommt immer wieder in die Situation, eine bestimmte Funktionalität in einer Serviceklasse zu kapseln (z.B. den Zugriff auf eine Datenbank oder das Dateisystem). Eine solche Serviceklasse on-demand zu instanziieren kann Ressourcen sparen. Doch das Wissen um den Aufwand, den eine Objekterzeugung benötigt, sollte nicht bei allen Konsumenten des Diensterbringers aufschlagen. Eine für den Verwender vollkommen transparente Möglichkeit, diese Information auf die Konfiguration der Anwendung zu beschränken, bietet die dynamische Erzeugung von Klassen mittels Reflection.Emit.

Angenommen ich habe einen Service, beschrieben durch das Interface IMyContract und implementiert in der Klasse MyService. Die Instanziierung von MyService ist, aus welchen Gründen auch immer, sehr zeitaufwendig und/oder ressourcenfressend. Außerdem wird dieser Service zwar an mehreren Stellen benötigt, aber nicht unbedingt in jedem Fall. Z.B. könnte ein MessageHandler in Abhängigkeit vom Inhalt einer Nachricht diesen oder jenen Service aufrufen. Ich möchte also keine fertige Instanz des Service in alle potentiellen Konsumenten injizieren, weil der Aufwand zur Erzeugung des Service häufig nicht gerechtfertigt ist.

Eine Lösung wäre, eine Factory über den Konstruktor zu injizieren. Dies kann im einfachsten Fall ein Delegate vom Typ Func<IMyContract> sein. Diesen kann ich nutzen, um mir im Fall der Fälle eine Instanz des Service zu besorgen. Verwendet man jetzt noch Lazy<T>, dann kann man das Ganze sogar recht hübsch machen.

   1:  public class MyConsumer
   2:  {
   3:    private readonly Lazy<IMyContract> lazy;
   4:    public MyConsumer(Func<IMyContract> serviceFactory)
   5:    {
   6:      this.lazy = new Lazy<IMyContract>(serviceFactory);
   7:    } 
   8:    public IMyContract Service
   9:    {
  10:      get { return this.lazy.Value; }
  11:    } 
  12:    public void DoSomething()
  13:    {
  14:      this.Service.DoSomething();
  15:    }
  16:  }

Das hat aber einen entscheidenden Nachteil: Ich injiziere eine Factory, weil ich weiß, dass meine Implementierung von IMyContract teuer in der Erzeugung ist. Eine andere Implementierung hat diesen Pferdefuß vielleicht gar nicht. Das ist eine sogenannte leaky abstraction. Das Wissen über eine Implementierung steuert, wie diese Implementierung verwendet wird. Dadurch kann ich sie nicht mehr beliebig austauschen.

Eine saubere Lösung würde MyConsumer einfach eine Implementierung von IMyContract übergeben. Wir haben keine leaky abstraction mehr. Pattern eingehalten, Soll erfüllt.

Die Erzeugung von MyService ist aber nun mal teuer. Also schieben wir diese akademische Diskussion beiseite und wählen einen “pragmatischen” Ansatz.

Allerdings entstehen Pattern und Best Practices nicht ohne Grund. Darum lohnt es sich, hier ein wenig mehr Hirnschmalz zu investieren.

Wenn mir mein DI-Container einen Proxy generieren würde, der im Kern eine Kapselung von Lazy<T> ist, und der MyService wirklich nur dann instanziiert, wenn er tatsächlich gebraucht wird, hätte ich das Performance-Problem gelöst, die leaky abstraction vermieden und das Wissen um die Kosten von MyService wäre auf die Konfiguration des Containers beschränkt (also genau da, wo man solche Entscheidungen auch treffen sollte).

Mit den Interception-Mechanismen von Unity oder Castle DynamicProxy kann man sich etwas derartiges zurechtbiegen. Aber schön ist die Lösung nicht und schneller wird die Anwendung dadurch auch nicht. Wrapper für jeden Service in einer Anwendung von Hand zu kodieren oder mit Hilfe von T4-Templates zu generieren erfordert immer noch manuelle Eingriffe durch den Entwickler.

Doch das muss nicht sein! Durch den Einsatz von Reflection.Emit kann man den IL-Code für die Wrapper generieren. Damit kombiniert man die Performance der handgefertigten Wrapper mit dem Komfort der dynamisch erzeugten Proxies.

Einen guten Einstieg in die IL-Programmierung bieten zwei Artikel auf The Code Project.

Den Wrapper kann man einmal von Hand kodieren und sich dann mittels Reflector den zugehörigen IL Code anschauen. Danach geht es daran herauszufinden, wie sich etwas gleichwertiges generieren lässt. Das ist nicht ganz einfach und läuft im Endeffekt auf jede Menge trial-and-error hinaus. Aber das Ergebnis lohnt den Aufwand.

Der generierte Proxy sieht in etwa folgendermaßen aus:

   1:  public class MyContract_LazyInstantiationProxy : IMyContract
   2:  {
   3:    private readonly Lazy<IMyContract> lazy;
   4:    public MyConsumer(Func<IMyContract> serviceFactory)
   5:    {
   6:      this.lazy = new Lazy<IMyContract>(serviceFactory);
   7:    } 
   8:    public IMyContract Service
   9:    {
  10:      get { return this.lazy.Value; }
  11:    } 
  12:    public void DoSomething()
  13:    {
  14:      this.Service.DoSomething();
  15:    }
  16:  }

Er implementiert IMyContract. Kapselt die Erzeugung des tatsächlichen Diensterbringers in einem Lazy<IMyContract> und delegiert einfach die eingehenden Aufrufe. Durch eine Extension-Methode für IUnityContainer gestaltet sich die Registrierung am Container denkbar einfach:

   1:  IUnityContainer container = new UnityContainer();
   2:  container.RegisterLazyProxy(
   3:    x =>
   4:      {
   5:        x.Contract = typeof(IFooService);
   6:        x.ServiceImplementation = typeof(FooService);
   7:      });

Der Proxy muss keine Performanceverluste durch die Interception-Infrastruktur hinnehmen. Er ist genauso schnell wie selbstgeschriebener Code. Die Implementierung von IMyContract kann weiterhin beliebig ausgetauscht werden, es ist lediglich eine kleine Änderung in der Konfiguration des Containers notwendig.

Bei Interesse kann der Quellcode zum Beitrag auf CodePlex heruntergeladen werden. Der Generator liegt unter TecX.Unity.Proxies. Die zugehörigen Tests, die seine Verwendung demonstrieren, sind unter TecX.Unity.Proxies.Test zu finden.

Caching transparent

Das Thema Caching kann man auf viele verschiedene Wege angehen. Einer davon ist ein vollkommen transparenter Caching-Layer, der Queries abfängt und entsprechend behandelt.

Über das Wie und das Was wird beim Thema Caching gerne und häufig diskutiert, auch unter eXperts. Meistens trennt man sich nach einer solchen Diskussion mit der Erkenntnis, dass es auch für Caching keine Silver Bullet gibt. Keine Lösung, die sich in jeder Situation bedingungslos bewährt.

Eine Lösung, für ein Szenario soll der folgende Beitrag vorstellen.

Ziel ist es, das Caching transparent zu implementieren. Ein Aufrufer soll gar nicht merken, dass das Ergebnis seiner Abfrage irgendwo zwischengespeichert wird. Der Cache kann damit auch jederzeit per Konfiguration zu- oder abgeschaltet werden, ohne dass der Code auf Seite des Verwenders geändert werden muss.

Um dieses Ziel zu erreichen werden alle Aufrufe an die eigentliche Datenzugriffskomponente abgefangen und entsprechend behandelt, bevor diese dann weitergereicht werden. Hierzu definieren wir zunächst ein Interface für die Datenzugriffskomponente.

   1:  public interface ICustomerRepository
   2:  {
   3:    IQueryable<Customer> Customers { get; }
   4:  }


Die Einführung von LINQ brachte das Interface IQueryable<T> mit. Dieses Interface ermöglicht die Definition einer Abfragebedingung, die erst evaluiert wird, wenn das Ergebnis der Abfrage verarbeitet wird (etwa durch den Aufruf von ToList() oder durch die Verwendung des Ergebnisses in einer foreach()-Schleife).

Um eine solche Abfragebedingung abfangen zu können muss man nun zunächst entsprechende Implementierungen von IQueryable<T> und dessen Basisinterface IQueryable erstellen.

Etwas vereinfacht könnten diese wie folgt aussehen.

   1:  public class QueryInterceptor<T> : QueryInterceptor, IQueryable<T>
   2:  {
   3:    private readonly IQueryable<T> wrapped;
   4:    public QueryInterceptor(IQueryable<T> wrapped, QueryInterceptorProvider provider)
   5:      : base(wrapped, provider)
   6:    {
   7:      this.wrapped = wrapped;
   8:    }
   9:    public IEnumerator<T> GetEnumerator()
  10:    {
  11:      var enumerable = this.Provider.Execute<IEnumerable<T>>(this.Expression);
  12:      var enumerator = enumerable.GetEnumerator();
  13:      return enumerator;
  14:    }
  15:  }
  16:   
  17:  public class QueryInterceptor : IQueryable
  18:  {
  19:    private readonly IQueryable wrapped;
  20:    private readonly QueryInterceptorProvider queryProvider;
  21:    public QueryInterceptor(IQueryable wrapped, QueryInterceptorProvider provider)
  22:    {
  23:      this.wrapped = wrapped;
  24:      this.queryProvider = provider;
  25:    }
  26:    public Type ElementType
  27:    {
  28:      get { return this.wrapped.ElementType; }
  29:    }
  30:    public Expression Expression
  31:    {
  32:      get { return this.wrapped.Expression; }
  33:    }
  34:    public IQueryProvider Provider
  35:    {
  36:      get { return this.queryProvider; }
  37:    }
  38:    public QueryInterceptorProvider QueryProvider
  39:    {
  40:      get { return this.queryProvider; }
  41:    }
  42:    IEnumerator IEnumerable.GetEnumerator()
  43:    {
  44:      var enumerable = this.Provider.Execute(this.Expression) as IEnumerable;
  45:      var enumerator = enumerable.GetEnumerator();
  46:      return enumerator;
  47:    }
  48:  }

Das genügt allerdings noch nicht ganz. LINQ verwendet zur Erstellung und Ausführung von Queries außerdem noch Implementierungen von IQueryProvider. Auch hierfür müssen wir einen Interceptor bereitstellen.

   1:  public class QueryInterceptorProvider : IQueryProvider
   2:  {
   3:    private readonly IQueryProvider wrapped;
   4:    public QueryInterceptorProvider(IQueryProvider wrapped)
   5:    {
   6:      this.wrapped = wrapped;
   7:    }
   8:    public event EventHandler<ExpressionExecuteEventArgs> Executing = delegate { };
   9:    public event EventHandler<ExpressionExecuteEventArgs> Executed = delegate { };
  10:    public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
  11:    {
  12:      var rawQuery = wrapped.CreateQuery<TElement>(expression);
  13:      var interceptor = new QueryInterceptor<TElement>(rawQuery, this);
  14:      return interceptor;
  15:    }
  16:    public IQueryable CreateQuery(Expression expression)
  17:    {
  18:      var rawQuery = this.wrapped.CreateQuery(expression);
  19:      var interceptor = new QueryInterceptor(rawQuery, this);
  20:      return interceptor;
  21:    }
  22:    public TResult Execute<TResult>(Expression expression)
  23:    {
  24:      object value;
  25:      bool handled = this.NotifyExecuting(expression, out value);
  26:      TResult result = !handled ? this.wrapped.Execute<TResult>(expression) : (TResult)value;
  27:      this.NotifyExecuted(expression, result);
  28:      return result;
  29:    }
  30:    public object Execute(Expression expression)
  31:    {
  32:      object value;
  33:      bool handled = this.NotifyExecuting(expression, out value);
  34:      object result = !handled ? this.wrapped.Execute(expression) : value;
  35:      this.NotifyExecuted(expression, result);
  36:      return result;
  37:    }
  38:    public bool NotifyExecuting(Expression expression, out object result)
  39:    {
  40:      var e = new ExpressionExecuteEventArgs { Expression = expression };
  41:      this.Executing(this, e);
  42:      if (e.Handled)
  43:      {
  44:        result = e.Result;
  45:        return true;
  46:      }
  47:      result = null;
  48:      return false;
  49:    }
  50:    public void NotifyExecuted(Expression expression, object result)
  51:    {
  52:      var e = new ExpressionExecuteEventArgs
  53:        {
  54:          Expression = expression, 
  55:          Result = result
  56:        };
  57:      this.Executed(this, e);
  58:    }
  59:  }

Vor und nach der Evaluierung einer Abfragebedingung feuert der QueryInterceptorProvider die Executing und Executed Events, auf die der Cache reagieren wird. Die zu diesen Events gehörenden ExpressionExecuteEventArgs sehen wie folgt aus.

   1:  public class ExpressionExecuteEventArgs : EventArgs
   2:  {
   3:    public bool Handled { get; set; }
   4:    public object Result { get; set; }
   5:    public Expression Expression { get; set; }
   6:  }

Diese EventArgs liefern die Expression, die die Abfragebedingung bildet. Diese Expression wird verwendet um einen eindeutigen Key für den Cache zu erzeugen. Ein Aufruf von ToString() auf der Expression reicht hierfür leider nicht. Warum das so ist und was sich dagegen tun lässt beschreibt Pete Montgomery in seinem Blog.

Mit diesen Komponenten ist es nun nur noch ein kleiner Schritt zum CachingCustomerRepository. Dieses verwendet die mit .NET 4.0 hinzugekommen Strukturen aus dem System.Runtime.Caching-Namespace. Denkbar ist aber auch jede andere Cache-Implementierung wie beispielsweise der AppFabric-Cache.

   1:  public class CachingCustomerRepository : ICustomerRepository
   2:  {
   3:    private readonly ICustomerRepository inner;
   4:    private readonly ObjectCache cache;
   5:    private QueryInterceptor<Customer> customers;
   6:    public CachingCustomerRepository(ICustomerRepository inner)
   7:    {
   8:      this.inner = inner;
   9:      this.cache = new MemoryCache(typeof(CachingCustomerRepository).FullName);
  10:      this.customers = new QueryInterceptor<Customer>(this.inner.Customers, new QueryInterceptorProvider(this.inner.Customers.Provider));
  11:      this.customers.QueryProvider.Executing += this.OnQueryExecuting;
  12:      this.customers.QueryProvider.Executed += this.OnQueryExecuted;
  13:    }
  14:    public IQueryable<Customer> Customers
  15:    {
  16:      get { return this.customers; }
  17:    }
  18:    private void OnQueryExecuted(object sender, ExpressionExecuteEventArgs e)
  19:    {
  20:      string cacheKey = e.Expression.GetCacheKey();
  21:      IQueryable<Customer> cachedResult = this.cache[cacheKey] as IQueryable<Customer>;
  22:      if (cachedResult == null)
  23:      {
  24:        var evaluatedQueryable = ((IEnumerable<Customer>)e.Result).ToList().AsQueryable();
  25:        this.cache[cacheKey] = evaluatedQueryable;
  26:      }
  27:    }
  28:    private void OnQueryExecuting(object sender, ExpressionExecuteEventArgs e)
  29:    {
  30:      string cacheKey = e.Expression.GetCacheKey();
  31:      IQueryable<Customer> cachedResult = this.cache[cacheKey] as IQueryable<Customer>;
  32:      if (cachedResult != null)
  33:      {
  34:        e.Handled = true;
  35:        e.Result = cachedResult;
  36:      }
  37:  }

Diese Klasse wrappt eine beliebige andere Implementierung von ICustomerRepository und erweitert deren Fähigkeiten vollkommen transparent um das Caching von Abfrageergebnissen. Dazu wird die Customers-Property in einen QueryInterceptor gepackt. Für die Executing/Executed-Events des zugehörigen QueryInterceptorProviders werden zwei Listener registriert. Der erste prüft vor der Abfrage, ob ein entsprechendes Ergebnis schon im Cache vorliegt und bedient die Abfrage gegebenenfalls aus dem Cache. Der zweite nimmt das Ergebnis in den Cache auf, falls es dort nicht schon vorhanden ist.

Die vorgestellte Lösung ist eine technische Machbarkeitsstudie. Sie legt sich vollkommen transparent um den Datenzugriff und verbirgt somit den Caching-Mechanismus komplett vor dem Aufrufer. Dadurch wird er von der Komplexität des Caching isoliert.

Allerdings hat er so auch keine Möglichkeit mit dem Wissen um den Kontext einer Abfrage Optimierungen beim Caching vorzunehmen.

Welche Performancegewinne sich mit einem sehr expliziten Umgang mit dem Caching erreichen lassen zeigt dieses Video. Es beschreibt, wie StackOverflow mit geringem Einsatz von Hardware die Antwortzeiten seiner Seiten kurz hält.

Und stets wiederkehrende Fragen muss der Verwender trotzdem für das jeweilige Szenario klären:

  • Muss tatsächlich jede Abfrage gecached werden?
  • Können Teile der Ergebnisse im Cache für andere Abfragen wiederverwendet werden?
  • Wiederholen sich Abfragen häufig genug um den Aufwand für das Caching zu rechtfertigen?
  • Was passiert bei Änderungen, beispielsweise durch ein Update(Customer)?
  • Bringt das Caching für das geplante Szenario tatsächlich Effizienzgewinne?
  • Beeinflusst das Caching die Konsistenz der Ergebnisse?

Wie bereits ganz zu Beginn angesprochen gibt es eben leider auch für das Caching keine allgemeingültige Lösung.

Das Command Pattern in WPF und Silverlight

Commanding ist ein anerkanntes Pattern zur Entkopplung von Anzeige und Anzeigelogik. Bei WPF und Silverlight ist es ganz tief im System verankert und erlaubt flexible, deklarative Lösungen für häufig wiederkehrende Probleme.

Wenn man ihn einmal hat, dann will man ihn nie wieder hergeben! Gemeint ist der Commanding-Mechanismus von WPF und Silverlight. Windows Forms haben ihn nicht und man kann ihn dort auch nur mit viel Aufwand nachbauen.

Man nehme beispielsweise eine TextBox, die als Suchfeld dient. Mit dem abschließenden Druck auf die Eingabetaste soll die Suche gestartet werden. Mit WPF kann das so einfach aussehen:

   1:  <TextBox x:Name="searchTextBox">
   2:    <TextBox.InputBindings>
   3:      <KeyBinding Command="{Binding Search}" Key="Enter"/>
   4:    </TextBox.InputBindings>
   5:  </TextBox>

Damit bindet man das in der Property Search des ViewModels hinterlegte ICommand an den Auslöser “Eingabetaste gedrückt” des Textfeldes.

Aber hier ist noch nicht Schluss. Man kann diesen Command-Aufrufen auch zusätzliche Parameter mitgeben.

Man stelle sich eine ListBox vor, die Suchergebnisse im Stile der Infocards in der Outlook-Inbox anzeigt.

Ausgewählte Elemente aus dieser Suchliste sollen nun in die Zwischenablage kopiert werden, um sie in anderen Anwendungen zu verwenden. Es soll aber auch die Möglichkeit geben alle Suchergebnisse auf einen Schlag zu kopieren.

Also definieren wir ein entsprechendes Command das wir ganz wagemutig CopySearchResultsToClipboardCommand nennen.

   1:  public class CopySearchResultsToClipboardCommand : ICommand 
   2:  { 
   3:    public void Execute(object parameter) 
   4:    { 
   5:      Guard.AssertNotNull(parameter, "parameter"); 
   6:      var list = parameter as IList; 
   7:      if (list != null) 
   8:      { 
   9:        var selectedSearchResults = list.OfType<SearchResult>(); 
  10:        string csv = CsvFormatter.ToCsv(selectedSearchResults); 
  11:        Clipboard.SetText(csv, TextDataFormat.UnicodeText); 
  12:      } 
  13:    } 
  14:  }

Dieses Command konvertiert die per Parameter übergebenen Datensätze in ein CSV-Format, das sowohl in einem Texteditor, als auch in Excel angezeigt werden kann.

Dieses Command wird in der Property Copy des ViewModels abgelegt.

   1:  public class ViewModel 
   2:  { 
   3:    public ICommand Copy { get; set; } 
   4:    public MainWindowViewModel() 
   5:    { 
   6:      this.Copy = new CopySearchResultsToClipboardCommand(); 
   7:    } 
   8:  }

Und jetzt kommt der interessante Teil. Wir binden das Command an die Tastenkombination CTRL+C

   1:  <Window.InputBindings> 
   2:    <KeyBinding 
   3:      Key="C" 
   4:      Modifiers="Ctrl" 
   5:      Command="{Binding Copy}" 
   6:      CommandParameter="{Binding ElementName=searchResults, Path=SelectedItems}"/> 
   7:  </Window.InputBindings> 

an einen Copy-Button

   1:  <Button Content="Copy" 
   2:    Command="{Binding Copy}" 
   3:    CommandParameter="{Binding ElementName=searchResults, Path=SelectedItems}"/> 

und an einen CopyAll-Button.

   1:  <Button 
   2:    Content="Copy all" 
   3:    Command="{Binding Copy}" 
   4:    CommandParameter="{Binding ElementName=searchResults, Path=Items}"/>

Wo ist der Unterschied zwischen den Buttons? Richtig! Der CommandParameter wird einmal mit den Werten aus der Property SelectedItems der ListBox und das andere Mal mit denen aus Items gefüttert.

Damit haben wir deklarativ ein Problem gelöst, das unter WinForms etliche Zeilen Code und eine Menge Aufwand für eine saubere Trennung zwischen View und ViewModel gekostet hätte.

Und falls sich jemand fragt, warum wir nicht ApplicationCommands.Copy verwendet haben: Commands kapseln Verhalten. Aber man kann kein eigenes Command an die Stelle eines ApplicationCommands setzen. Über ein CommandBinding lassen sich nur EventHandler an diesen ApplicationCommands einhängen. Das kann man sicher auch “schön” hinbekommen, aber es erscheint unnötig kompliziert, wenn man mit einem eigenen ICommand bereits eine saubere Kapselung zur Hand hat. Der häufig bevorzugte Weg ist daher der, per Binding auf Commands zuzugreifen, die über Properties am ViewModel angeboten werden. Dafür ist WPF ja so gut bei Data/Command/Input-Binding 🙂

WCF Express Interop Bindings: WCF spricht JAVA

Industrieweite Standards dienen der Interoperabilität von Produkten unterschiedlicher Hersteller. In der Vergangenheit hat Microsoft häufig durch eine recht eigenwillige Umsetzung dieser Standards geglänzt. Umso bemerkenswerter ist, dass Microsoft als einziger Hersteller mit der Windows Communication Foundation (WCF) den vollständigen Stack der WS-*-Protokolle implementiert. Mit WCF erhält man also prinzipiell die Möglichkeit mit allen standardkonformen Diensten im Netz zu interagieren. >> mehr…

Testbarkeit und das Entity Framework

Auch wenn das Thema Testbarkeit wahrlich kein neues mehr ist, so gibt es doch immer wieder Neues dazu zu lernen. Die Version 1.0 des Entity Framework (EF) hatte bezüglich der Testbarkeit noch etliche Defizite, die mit der Version 4.0 (und dem kürzlich erschienenen Update auf die Version 4.1) von Microsoft angegangen wurden.

Die große Schwachstelle, über die ich bei der täglichen Arbeit mit dem EF1 häufig stolperte: Die vom Designer generierten Klassen mit dem Ballast aus ChangeTracking und ChangeNotification und der ObjectContext für den Datenzugriff waren eng miteinander verwoben und für UnitTests wenig geeignet.

Mit EF4 kam der Support für Plain Old CLR Objects (POCO) und austauschbare Templates für die Generierung von Entities. Und plötzlich wurde vieles möglich.

In seinem Artikel Testability and Entity Framework erläutert Microsoft MVP Scott Allen detailliert, wie man mit verblüffend einfachen Mitteln aus dem Monolithen Datenzugriff eine durch TestDouble ersetzbare Komponenten macht. Er erklärt, was testbare Komponenten ausmacht. Wie die Patterns Repository und UnitOfWork zusammenspielen und wie man sie zur Kapselung der Datenhaltung einsetzt.

Gut verständlich zeigt er verschiedene Ausbaustufen der Abstraktion vom Entity Framework als Zugriffsschicht. Vom vollständigen Verbergen des Entity Framework hinter der Fassade eines Repository bis zur Verwendung von Interfaces, die das Entity Framework mitbringt. Er erläutert welche Kompromisse bei der Einhaltung von Persistence Ignorance (PI) möglich sind und was man als Gegenwert für diese Kompromisse geboten bekommt. Durch die Verwendung einer Extension-Methode erhält man z.B. die Möglichkeit Fetch-Paths mittels Include() anzugeben (unter EF4.1 funktioniert das auch mittels typsicherer Expressions anstelle von Magic Strings). Die Deklarierung von Properties als virtual ermöglicht implizites lazy-loading und den Komfort von automatischem ChangeTracking ohne dafür selbst Code schreiben zu müssen.

Fazit: Absolut lesenswert! Als großer Fan von einfachen Lösungen für komplizierte Probleme war ich von Scott Allens Artikel begeistert. Der Autor hat es geschafft großen Mehrwert in wenig Text zu packen. Eine halbe Stunde für das Lesen des Artikels. Zwei Stunden um mit den vorgestellten Beispielen zu experimentieren. Und plötzlich kann man ungezählte Arbeitsstunden für manuelle Fehlersuche einsparen.

Viele Wege führen nach Rom (IEqualityComparer)

Für ein Problem gibt es häufig viele Lösungen.Für kaum ein Arbeitsfeld gilt das so sehr wie für die Informatik, wo es häufig dutzende konkurrierender Ansätze gibt. Ein Beispiel dafür, wie mannigfaltig das Spektrum an Lösungen sein kann, zeigte sich kürzlich in einem Projekt, als es darum ging ein Kreuzprodukts über einen selbstgeschriebenen Datentypen zu erzeugen. Für dieses spezielle Kreuzprodukt gilt das aus der Mathematik bekannte Kommutativgesetz (a*b = b*a). D.h. für eine Kombination aus zwei Objekten dieses Typs ist es gleich, ob man ein Paar (InstanzA, InstanzB) oder das “umgekehrte” Paar (InstanzB, InstanzA) vor sich hat.

Mittels Linq ist es ein Leichtes, ein solches Kreuzprodukt zu berechnen:

var crossProduct = from b1 in blocks
                  from b2 in blocks
                  where b1.Id != b2.Id &&
                          b1.Length + b2.Length <= parameters.MaximumSizeInMeters &&
                          b1.Weight + b2.Weight <= parameters.MaximumWeightInTons
                  select new { Block1 = b1, Block2 = b2 };

Allerdings erhält man hierdurch beide Paare (A,B) und (B,A). Es böte sich an dieser Stelle an, mit einem Aufruf der Extension-Methode Distinct(), alle Duplikate herauszufiltern.

Diese Methode funktioniert zwar prinzipiell mit anonymen Datentypen (also den Objekten, die ich mittels new {Block1, Block2} erzeuge). Es gibt jedoch keinen (direkten) Weg, der Abfrage beizubringen, dass die Reihenfolge der Elemente eines Paares in diesem Fall keine Rolle spielt.

Für die Methode Distinct() gibt es aber eine Überladung, die einen Parameter vom Typ IEqualityComparer<T> erwartet. Implementierungen dieses Interface werden verwendet um Objekte auf Gleichheit zu prüfen und funktionieren analog zum Überschreiben der Methoden Equals() und GetHashCode(). Der Vorteil ist, dass man diese Comparer jederzeit austauschen kann, wohingegen Änderungen an den überschriebenen Methoden immer mit Vorsicht zu genießen sind, weil schnell unerwartete Seiteneffekte auftreten.

Doch zunächst einmal braucht man eine Implementierung von IEqualityComparer<T>, der man on-the-fly Vergleichs- und Hashfunktion mitgeben kann. Diese Implementierung heißt LambdaEqualityComparer:

public class LambdaEqualityComparer<T> : EqualityComparer<T>
{
   private readonly Func<T, T, bool> equals;
   private readonly Func<T, int> hash;

   public LambdaEqualityComparer(Func<T, T, bool> equals)
       : this(equals, obj => obj.GetHashCode())
   {
   }

   public LambdaEqualityComparer(Func<T, T, bool> equals, Func<T, int> hash)
   {
       if (equals == null) throw new ArgumentNullException("equals");
       if (hash == null) throw new ArgumentNullException("hash");

       this.equals = equals;
       this.hash = hash;
   }

   public override bool Equals(T x, T y)
   {
       if (x == null) throw new ArgumentNullException("x");
       if (y == null) throw new ArgumentNullException("y");

       return equals(x, y);
   }

   public override int GetHashCode(T obj)
   {
       if (obj == null) throw new ArgumentNullException("obj");

       return hash(obj);
   }
}

Und um diesen für anonyme Typen verwenden zu können kommt ein weiteres Feature aus .NET3.0 zum Einsatz: Extension-Methoden.

public static class EnumerableExtensions
{
   public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items,
       Func<T, T, bool> equals, Func<T, int> hash)
   {
       if (items == null) throw new ArgumentNullException("items");
       if (equals == null) throw new ArgumentNullException("equals");
       if (hash == null) throw new ArgumentNullException("hash");

       return items.Distinct(new LambdaEqualityComparer<T>(equals, hash));
   }
}

Damit kann man folgende Abfrage definieren, die das Kreuzprodukt mit lediglich einem Repräsentanten jeder Kombinationsmöglichkeit liefert:

var crossProduct = (from b1 in blocks
                   from b2 in blocks
                   where b1.Id != b2.Id &&
                           b1.Length + b2.Length <= parameters.MaximumSizeInMeters &&
                           b1.Weight + b2.Weight <= parameters.MaximumWeightInTons
                   select new { Block1 = b1, Block2 = b2 })

                   .Distinct((x, y) =>
                                       {
                                           if (x.Block1.Id == y.Block1.Id && x.Block2.Id == y.Block2.Id)
                                               return true;

                                           if (x.Block1.Id == y.Block2.Id && x.Block2.Id == y.Block1.Id)
                                               return true;

                                           return false;
                                       },
                                                  
                               x => x.Block1.Id.GetHashCode() ^ x.Block2.Id.GetHashCode());

Diese Lösung verwendet einige Bausteine aus dem .NET 3.x Feature-Set und zeigt durchaus eindrucksvoll, wie mächtig diese Funktionen sein können. Allerdings leidet durch die Verschachtelung der Abfragen für das eigentliche Kreuzprodukt und der Vergleichslogik die Lesbarkeit sehr stark. Eine sehr viel leichter zu durchschauende Lösung würde entstehen, wenn man den Comparer durch ein simples new() erzeugen, und als Parameter verwenden könnte. Dafür müsste man allerdings auf die Verwendung von anonymen Typen verzichten. Eine solche Lösung sähe dann folgendermaßen aus:

[DebuggerDisplay("{Block1.Id} {Block2.Id}")]
public class BlockPair
{
   public Block Block1 { get; set; }
   public Block Block2 { get; set; }
} 

Steht statt eines anonymen Typen ein deklarierter .NET-Datentyp zur Verfügung, so kann auch der Comparer durch eine spezifische, dafür aber einfachere, Implementierung ersetzt werden.

public class CompareCrossProduct : IEqualityComparer<BlockPair>
{
   public bool Equals(BlockPair x, BlockPair y)
   {
       if (x.Block1.Id == y.Block1.Id && x.Block2.Id == y.Block2.Id)
           return true;

       if (x.Block1.Id == y.Block2.Id && x.Block2.Id == y.Block1.Id)
           return true;

       return false;
   }

   public int GetHashCode(BlockPair x)
   {
       return x.Block1.Id.GetHashCode() ^ x.Block2.Id.GetHashCode();
   }
} 

Und so erhält man wieder eine deskriptive Abfrage, die man nicht erst gedanklich kompilieren muss, um sie zu verstehen:

var crossProduct = (from b1 in blocks
                   from b2 in blocks
                   where b1.Id != b2.Id &&
                         b1.Length + b2.Length <= parameters.MaximumBlockSizeInMeters &&
                         b1.Weight + b2.Weight <= parameters.MaximumBlockWeightInTons
                   select new BlockPair { Block1 = b1, Block2 = b2 })
                  .Distinct(new CompareCrossProduct());

Einen Pferdefuß haben allerdings beide Lösungen noch. Durch den Vergleich b1.Id != b2.Id handelt es sich immer um eine Abfrage mit quadratischer Komplexität O(n2). Mit dieser Überlegung im Hinterkopf ergibt sich noch eine dritte Lösung. Durch zwei ineinander geschachtelte Schleifen kann man die die Prüfung der Paarungen geschickt umgehen.

List<Block> blockList = new List<Block>(blocks);
List<BlockPair> crossProduct = new List<BlockPair>();

for (int i = 0; i < blockList.Count; i++)
{
   for (int j = i + 1; j < blockList.Count; j++)
   {
       Block b1 = blockList[i];
       Block b2 = blockList[j];

       if (b1.Length + b2.Length <= parameters.MaximumSizeInMeters &&
           b1.Weight + b2.Weight <= parameters.MaximumWeightInTons)
       {
           crossProduct.Add(new BlockPair { Block1 = b1, Block2 = b2 });
       }
   }
} 

Keine Lambdas, kein Linq. Technologisch vollkommen unaufgeregt. Und doch funktioniert dieser Ansatz mindestens genauso gut, wie die beiden vorherigen. Die innere Schleife beginnt eine Position hinter dem aktuellen Laufindex der äußeren zu zählen. Dadurch kommen keine Permutationen bei der Kombination zustande und man kann zwei Instanzen des Datentyps, die die vorgegebenen Rahmenbedingungen einhalten, ganz einfach miteinander verknüpfen.

Wie man deutlich sieht erlauben neue Technologien dem Entwickler erhöhten Freiraum bei der Umsetzung von Anforderungen. Viele Aufgaben lassen sich komfortabler und schneller lösen. Doch wie so häufig gilt auch hier, dass man genau abwägen muss, ob eine technologisch machbare Lösung zugleich auch eine für das Projekt vorteilhafte ist.

Inspizieren von binär kodierten WCF Nachrichten

Fiddler ist das Standardwerkzeug zur Untersuchung von Web-Traffic. Er hängt sich als Proxy zwischen den eigenen PC und das Internet und erlaubt die detailierte Analyse ein- und ausgehenden HTTP(S) Verkehrs.

Möchte man jedoch die binär kodierten Nachrichten einsehen, die ein Silverlight Client mit einem WCF-Service austauscht, so wird es problematisch, weil Fiddler dieses Protokoll von Haus aus nicht beherrscht.

Microsoft bietet jedoch eine Erweiterung für Fiddler an, die diese Lücke schließt. Allerdings findet sich auch in der sehr flexibel erweiterbaren WCF eine Stelle, an der sich die Untersuchung von Nachrichten einbinden lässt. Dazu folgende Diskussion aus dem SDX Portal:

WCF Binary-encoded Message Inspector for Fiddler

Bislang habe ich beim Gespann Silverlight/Fiddler immer auf text encoding umgestellt um zu sehen, was über die Leitung geht (mit dem entsprechenden Aufwand).

Jetzt bin ich zufällig drüber gestolpert, dass man Fiddler beibringen kann, das binary encoding selbst zu decoden: http://code.msdn.microsoft.com/wcfbinaryinspector

Komentar 1:

Zwar nicht viel einfacher und mit etwas Aufwand: Hier beim Kunden wird für das Erstellen der WCF-Proxies eine Factory genutzt. Diese erstellt zu Laufzeit um den Proxy herum einen oder mehre weitere Proxies (Kaskade von Wrappern). Aktuell gibt es Proxies für Logging, Fehlerhandling usw. Wie passt da Ganze hier rein? ich habe mir mit 20 Zeilen Code einen Proxy geschrieben, der Request und Response in eine Datei legt. Dabei ist das Binding vollkommen egal, da dies vor dem eigentlichen WCF-Aufruf passiert. Für "Wie habt ihr uns aufgerufen und was habt ihr reingeschickt" ist das eine große Hilfe. Vor allem später in Produktion kann das Ganze mit einer Einstellung eingeschaltet werden. (unser Service greift auf 5 andere zu). Worauf ich hinaus will: Fiddler ist nett, habe ich auch auf meiner Kiste, aber so wie man sich Gedanken zu Logging und Tracing macht sollte man hier auch etwas Hirnschmalz reinstecken.

Komentar 2:

WCF bietet auch Infrastruktur für die Untersuchung ein- und ausgehender Nachrichten an
http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageinspector.aspx

Komentar 3:

Gefällt mir. Einziges Manko: man kann Request und Response nicht einander zuordnen. Also wenn ich einen Proxy habe und 3 Nachrichten drüber schicke (multithreaded, async, …) weiß ich nicht mehr wer zu wem gehört. Ich wollte eben im Dateinamen immer gleich sehen können welche Response zu welchem Request gehört.

Komentar 4:

Das kriegst du quasi geschenkt mit dazu.
BeforeSendRequest gibt einen correlationState vom Typ Object zurück. Dort kannst du hineinpacken was du möchtest. Standard ist die Verwendung einer eindeutigen Guid.
Und AfterReceiveReply bekommt vom Framework diesen correlationState gefüttert. Et voilá, du hast deine Zuordnung.