jenswinter.com
Software Development 24/7

Einführung in das Managed Extensibility Framework (Teil 2)

October 5, 2008 22:55 by Jens

Bisherige Artikel der Serie:


Im ersten Artikel dieser Serie ist beschrieben, was das Managed Extensibility Framework ist und welche Möglichkeiten es bietet. In diesem Artikel werde ich eine erste Einführung in die Verwendung des MEF zeigen. Anhand einer einfachen Demo-Anwendung soll der Einsatz demonstriert werden. Programme, die das MEF einsetzen, müssen die Assembly System.ComponentModel.Composition referenzieren. Sie kann hier heruntergeladen werden.

In der Demo-App, einem einfachen WPF-Programm, soll ein TabControl mit bestimmten Seiten gefüllt werden. So sieht das Ergebnis aus:



In einem ersten Schritt zeige ich die Umsetzung ohne den Einsatz von MEF. Die Anwendung besteht aus einem Hauptfenster, welches ein TabControl enthält und drei UserControls, die als Seiten in das TabControl geladen werden.

XAML-Code des Hauptfensters:

<Window x:Class="MefDemoApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="500" Width="600">

    <Grid>
        <TabControl ItemsSource="{Binding}" DisplayMemberPath="Title">
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <ContentPresenter Content="{Binding Page}"/>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

CodeBehind des Hauptfensters:

public partial class MainWindow : Window
{
    public UserControl Page1 = new Page1();
    public UserControl Page2 = new Page2();
    public UserControl Page3 = new Page3();

    public MainWindow()
    {
        InitializeComponent();

        DataContext = new List<object>
                          {
                              new {Title = "Page 1", Page = Page1},
                              new {Title = "Page 2", Page = Page2},
                              new {Title = "Page 3", Page = Page3}
                          };
    }
}

Der DataContext des Hauptfensters wird mit einer Liste von anonymen Objekten geladen, die jeweils einen Titel und die entsprechende Seite enthalten. Die Titel-Eigenschaft wird für die Beschriftung des Tabs verwendet. Wie im XAML-Code zu sehen ist, wird die ItemsSource des TabControls an den DataContext gebunden und der Content der Tab-Seiten an die Page-Eigenschaft gebunden.
Die Klassen Page1, Page2 und Page3 sind UserControls mit beliebigem Inhalt.

Ein erstes Problem, das im Quelltext zu sehen ist besteht in der direkten Abhängigkeit zu den UserControls. Die Erzeugung der Seiten mittels new Page1() reduziert die Wartbarkeit und die Erweiterbarkeit. Das Hauptfenster sollte nicht dafür verantwortlich sein, welche Seiten angezeigt werden. Erst recht sollte es die Seiten nicht selbst erzeugen.

Die wichtigsten Bestandteile des MEF sind der Katalog und der CompositionContainer. Der Katalog ist verantwortlich für Bereitstellung von Erweiterungen und der CompositionContainer sorgt für die Erzeugung dieser Erweiterungen und der Erfüllung der Abhängigkeiten.
Eine Erweiterung wird im MEF ComposablePart genannt. Ein ComposablePart enthält ein oder mehrere Komponenten (Exports), die anderen ComposableParts zur Verfügung gestellt werden. Es kann Abhängigkeiten zu anderen ComposableParts definieren. Diese Abhängigkeiten werden Imports genannt. Der CompositionContainer erzeugt ein ComposablePart und füllt die als Import deklarierten Komponenten mit den Komponenten, die als Export deklariert sind. Die Verbindung eines Imports mit einem Export ist möglich, da ein Contract zwischen Import und Export definiert wird. Der CompositionContainer kann über diesen Contract feststellen, welche exportierte Komponente zu welcher importierenden Komponente gemappt werden muss.

Die Deklaration der UserControls sieht bei der Verwendung des MEF nun so aus:

[Import("Page1")]
public UserControl Page1;

[Import("Page2")]
public UserControl Page2;

[Import("Page3")]
public UserControl Page3;

Wie hier zu sehen ist, werden die Instanzen nicht mehr explizit mittels new erzeugt. Stattdessen sind sie mit einem Import-Attribut versehen. Jedes Import-Attribut erthält eine Zeichenkette, die den Contract zum jeweiligen Export darstellt. Der CompositionContainer wird versuchen die Felder, die mit einem Import gekennzeichnet sind, mit einer passenden Komponente zu initialisieren.

Dafür müssen die UserControls natürlich als Export deklariert werden. Der CodeBehind eines UserControls sieht dann so aus:

[Export("Page1")]
public partial class Page1 : UserControl
{
    public Page1()
    {
        InitializeComponent();
    }
}

Die Klasse wird mit dem Export-Attribut versehen. Das Attribut erhält hier die Zeichenkette "Page1". Das ist der Contract, über den Imports mit derselben Bezeichnung verknüpft werden können. Die Contract-Bezeichnung kann im Export-Attribut weggelassen werden. Ist das der Fall, wird der Klassenname als Contract-Bezeichnung verwendet.

Jetzt fehlt eigentlich nur noch die Herstellung der Verbindung zwischen exportierten und importierenden Parts. Diese Aufgabe übernimmt der CompositionContainer. Im folgenden Quelltext ist zu sehen, wie der Konstructor des Hauptfensters erweitert wurde:

public MainWindow()
{
    InitializeComponent();

    var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
    var container = new CompositionContainer(catalog.CreateResolver());
    container.AddPart(this);
    container.Compose();

    DataContext = new List<object>
                      {
                          new {Title = "Page 1", Page = Page1},
                          new {Title = "Page 2", Page = Page2},
                          new {Title = "Page 3", Page = Page3}
                      };
}

Ein spezieller Katalog wird erzeugt, damit Exports und Imports gefunden werden können, die sich in der aktuellen Assembly befinden. Neben dem AttributedAssemblyPartCatalog gibt es noch diese Katalog-Varianten:
  • AttributedTypesPartCatalog - lädt Erweiterungen, die als Typen angegeben wurden
  • AggregatingComposablePartCatalog - fässt mehrere Cataloge zusammeny
  • DirectoryPartCatalog - lädt Erweiterungen aus einem angegebenen Verzeichnis

Der CompositionContainer wird erzeugt und erhält dabei eine ValueResolver-Instanz des Kataloges. Der Container benötigt diesen Resolver um die einzelnen Instanzen der angeforderten Erweiterungen erzeugen zu können. Nun muss nur noch mittels container.AddPart(this) die aktuelle Instanz des Hauptfensters hinzugefügt werden. Jetzt hat der Container alle Informationen um beim Aufruf der Compose()-Methode alle notwendigen Erweiterungen zusammenzusammeln und die Abhängigkeiten zu mit korrekten Instanzen zu füllen.
In dem vorliegenden Beispiel erkennt das MEF, dass die MainWindow-Instanz Parts importiert, die die Contracts "Page1", "Page2" und "Page3" haben. Dem CompositionContainer wurde ein Katalog zur Verfügung gestellt wurde, der ein exportierenden Part für jeden dieser Contracts enthält. Daher kann im Compose()-Aufruf auch das Setzen der einzelnen Seiten stattfinden.

Was haben wir eigentlich erreicht? Ich gebe zu, der Quelltext ist nicht gerade hübscher geworden. Für dieselbe Funktionalität ist er zudem auch noch um einige Zeilen gewachsen. Allerdings haben wir eine direkte Abhängigkeit zu den UserControls etwas "aufgeweicht". Dort wo vorher die Typen und deren Konstruktor-Aufrufe standen, haben wir nun eine Abstrahierung in Form von Kontrakten.

Noch besser ist, dass an dieser Stelle nicht Schluss ist. Das hier gezeigte Beispiel war nur ein kleiner Auschnitt. In folgenden Artikeln werde ich auf die fortgeschritteren Möglichkeiten des MEF eingehen.

Der Quelltext der Beispiel-Anwendung kann hier heruntergeladen werden. 

Einführung in das Managed Extensibility Framework (Teil 1)

September 29, 2008 22:33 by Jens
Anfang September wurde die zweite Preview eines interessantes Projektes des .NET Framework Teams auf Codeplex veröffentlicht. Es handelt sich dabei um das Managed Extensibility Framework (MEF). Die Projekt-Homepage befindet sich unter http://www.codeplex.com/mef.

Das MEF ist ein Framework, welches die Entwicklung von erweiterbaren .NET Anwendungen ermöglicht. Die Wiederverwendung und Erweiterung von Komponenten wird damit in Zukunft um einiges einfacher.
Bisher wurden Anwendungen erweiterbar und dynamisch entwickelt, indem mühselig eine Plugin-Infrastruktur eingebaut werden musste. Große Teile dieser Infrastruktur mussten sich um das dynamische Laden von Assemblies und Type kümmern. Viele Zeilen Quelltext sind geschrieben worden, um per Reflection auf externe Komponenten zuzugreifen.
Mit dem MEF wird dem Entwickler ein Großteil der Arbeit abgenommen.

In einer Artikelserie werde ich in die Verwendung das Managed Extensibility Frameworks einführen.

Was bietet das MEF?

Mit Hilfe des MEF können Anwendungen um Funktionalitäten erweitert werden, die sich in externen Komponenten befinden. Diese Komponenten können wiederum andere externe Komponenten verwenden. Für die Auflösung der Abhängigkeiten sorgt dabei das Framework. Anwendungsentwickler müssen sich also nur noch um die Implementierung der Funktionalitäten kümmern. Das Verknüpfen der Bestandteile wird komplett vom MEF übernommen.

Das Framework verfügt dabei über eine Reihe von Möglichkeiten, die benötigten Komponenten zu finden, einzusammeln und zu laden.

Die Erweiterungen können mit Meta-Informationen versehen werden. Dies erlaubt das Abfrufen und Filtern bestimmter Komponenten.

Im nächsten Artikel werde ich die Funktionsweise und Verwendung anhand einer kleinen Beispielanwendung demonstrieren. 

Hello @DotNetGerman Bloggers

September 29, 2008 21:33 by Jens

Ein herzliches Dankeschön an Alex für die Aufnahme meines Blogs in die Liste der deutschsprachigen .NET Blogger. Die Community Site ist zu erreichen unter http://dotnetgerman.com/.

Die Aufnahme ging übrigens mit dem Hinweis einher, dass bei .NET German Bloggers nur deutschprachige Beiträge gelistet werden sollen. Da ich in Zukunft wieder vermehrt deutschsprachigen Content - ähm, ich meine Inhalt - posten werde, dürfte diese Voraussetzung erfüllt sein. :)


Abhängigkeiten visuell aus Code erzeugen

September 25, 2008 21:42 by Jens
In der deutschsprachigen ALT.NET-Mailingliste ist eine sehr interessante Diskussion über die Erzeugung eines visuellen Abhängigkeitsgraphen aus dem Quelltext heraus entstanden. Der Gedanke, aus bestehendem Quelltext eine Architekturdokumentation generieren zu lassen klingt sehr vielversprechend.

Ralf Westphal schrieb ein Posting, in dem er fragte, wie man ein Fluent API dafür aufbauen könnte. Seine Idee sieht dabei in etwa so aus:

Konfiguration:

DIContainer.Instance
    .Root<IServiceA, ServiceA>()
        .uses<IServiceB, ServiceB>();
        

Dazugehöriger Quelltext:

class ServiceA : IServiceA
{
    private IServiceB _sb;

    public ServiceA()
    {
        _sb = DIContainer.Instance.Get<IServiceB>();
    }
}


Generierung des Graphen:

Bitmap bmp = DIContainer.Instance.DependencyGraph.ToBitmap();


Es gibt nur ein Problem, das ich bei dem Ansatz noch sehe. Es verletzt das DRY-Prinzip. Ralf konnte mich bisher noch nicht restlos vom Gegenteil überzeugen. Die Information der Abhängigkeit ist an zwei Stellen vorhanden. Einmal in der Konfiguration des Containers und ein zweites mal im Quelltext selbst.

Momentan bin ich der Überzeugung, dass man mit Hilfe des Managed Extensibility Frameworks diese Wiederholung der Informationen aufheben könnte. Ich forsche aber noch. :)

MEF is on CodePlex now

September 6, 2008 22:15 by Jens

Today Glenn Block announced that the first source bits of the Managed Extensibility Framework are out on CodePlex now.

This looks like a really interesting project. I think it could be very useful for some projects I'm currently working on. Tonight I'm going to explore the source a little bit. I'm especially interested in how it could be leveraged with Smart Client applications that are based on Prism.

From the project site:

The Managed Extensibility Framework (MEF) is a new library in .NET that enables greater reuse of applications and components. Using MEF, .NET applications can make the shift from being statically compiled to dynamically composed. If you are building extensible applications, extensible frameworks and application extensions, then MEF is for you. 

 


Private beta of StackOverflow.com

August 22, 2008 19:09 by Jens

Yesterday I received my login credentials for the private beta of stackoverflow.com! This is awesome.

I suppose I will spend most of the weekend browsing stackoverflow, asking questions and voting answers. StackOverflow is a social community for software developers. It is being developed by none less than Joel Spolsky and Jeff Atwood.

The concept of StackOverflow is based on questions that can be published by each user. They can be answered by others. All questions and answers can be voted on. This way the users gain reputation points and special badges. This is a very addictive concept.

I already put out a question and I was stunned when I saw it already answered after I refreshed the page. This is ridiculous. No kidding!

This site has huge potential. According to Jeff it will go live at the end of August. Until then you could listen to the stackoverflow podcast at http://blog.stackoverflow.com/.


Frühe Exits

August 11, 2008 23:24 by Jens

Genau wie Stefan bin ich ein Freund früher Exits. Sein Vorschlag sieht so aus:

public void DoSomething() {
    if (!a) {
        return;
}
    if (!b) {
        return;
}
    if (!c) {
        return;
}
    DoItRealy();
}

Ich hätte da aber noch einen kleinen Zusatz.

Die frühen Exits sollten so kurz wie möglich gehalten werden.
Bei frühen returns und throws handelt es sich um Guard Clauses, die nichts direkt mit dem Eigentlichen "Fleisch" der Methode zu tun haben und somit beim Lesen des Codes einen leichten Noise-Charakter haben. Das gefühlte Gewicht sollte m.M.n. so weit es geht auf dem wichtigen Teil der Methode liegen. Wenn ich z.B. wissen will, was darin passiert, will ich die Guards so schnell es geht überspringen können und nur bei Bedarf dort nachschauen.
Die Guards abzukürzen bedeutet, dass ich dabei sämtliche unnötigen Klammern weglasse. Das spart nämlich die eine oder andere Noise-Zeile ein.

public void DoSomething() {
    if (!a)
        return;
    if (!b)
        return;
    if (!c)
        return;
DoItRealy();
}

Oftmals habe ich auch die noch stärker abgekürzte Variante gesehen, in der das "return" in derselben Zeile wie das jeweils dazugehörende "if" steht:

public void DoSomething() {
    if (!a) return;
    if (!b) return;
    if (!c) return;
DoItRealy();
}

Das sieht auch sehr kompakt aus und ist ziemlich gut lesbar. Aber wie so Vieles ist das Geschmacksache.


Tags:
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Erste deutschsprachige ALT.NET Open Space Konferenz

August 10, 2008 13:46 by Jens

Da komm' ich gerade aus dem Urlaub zurück, und werde mit tollen Neuigkeiten überschüttet. Die beste Neuigkeit kam vom Stefan Lieser:

Am 18./19. Oktober wird die erste deutschsprachige ALT.NET Open Space Konferenz stattfinden. Der Veranstaltungsort ist die Mediencampus Villa Ida in Leipzig.
Es wird Diskussionen zu den folgenden Themen geben:

  • ALT.NET
  • Mobile Computing
  • Soft Skills

Ich bin auch besonders gespannt auf das Open Space-"Konferenz" Format.

Weitere Informationen bekommt man unter http://netopenspace.de.


Stefan Lieser: Software Design Principles

August 10, 2008 13:21 by Jens

Stefan Lieser wird am 16.09. als Redner bei der .NET User Group in Braunschweig zu Gast sein. Darauf freue ich mich besonders, da er einen Vortrag über Software Design Principles halten wird - ein Thema, das mir sehr am Herzen liegt.


Composite Application Guidance RTM gone live

July 4, 2008 06:26 by Jens

Not even a week after the release candidate had been published the final drops have been released.

So say Hello to the Composite Application Guidance (f.k.a. Prism) and get the bits here. The codeplex project homepage is at http://www.codeplex/compositewpf.


Prism RC1 released

June 28, 2008 15:02 by Jens

Today the Prism Composite Application Guidance for WPF team (Gosh, what a name!) published the first release candidate.

The Composite Application Guidance for WPF is designed to help you more easily build enterprise-level Windows Presentation Foundation (WPF) client applications. This guidance will help you design and build flexible composite WPF client applications – applications that use loosely coupled, independently evolvable pieces that work together within the overall application.

The release description states that the final release will be on MSDN within a couple of weeks.


Was ist ALT.NET?

June 24, 2008 22:56 by Jens

Hier mal mein Versuch den Begriff "ALT.NET" in einer Xing-Gruppe
(https://www.xing.com/app/forum?op=showarticles;id=7137858;articleid=7137858#7137858) zu beschreiben:

"Soweit ich das überblicken kann wurde dieser Begriff erstmals von David Laribee erwähnt und umschrieben:
http://laribee.com/blog/2007/04/10/altnet/

ALT.NET beschreibt eine bestimmte Einstellung des Entwicklers. Dieser zeichnet sich dadurch aus, dass er nicht bereit ist, sich Mainstream-konform zu verhalten. Vielmehr steuert er dagegen und ist ständig und aktiv auf der Suche nach besseren Wegen und Tools, um Ziele zu erreichen. Mit Wegen und Tools sind hier sämtliche Mittel der Softwareentwicklung gemeint. Das sind neben bspw. Entwicklungsumgebungen und Entwicklertools auch Programmiermethoden und Paradigmen. Ich würde sage, das Ganze hat mit Microsoft direkt nichts zu tun.
Obwohl sich viele Erkenntnisse der ALT.NET-Community gegen Microsoft und dessen vorgegebenen und empfohlenen Wegen richten. Das liegt aber eigentlich nur daran, dass Microsoft den größten  Einfluss auf die Entwicklergemeinschaft hat und somit den Mainstream definiert. Der brave .NET-Entwickler trabt da natürlich einfach hinterher, ohne sich zu fragen, ob das was MS vorgibt überhaupt das Beste ist.

Ein Beispiel:
Über die DataSet-Klasse gibt es z.B. tonnenweise Zeitschriftenartikel. Ein Designer dafür ist fest ins Visual Studio eingebaut. Ich würde das DataSet also als ziemlich "mainstream" bezeichnen. Trotzdem wird fast jeder mal so seine Schwierigkeiten damit gehabt haben.
ALT.NET ist jemand, der nach Möglichkeiten sucht, die Ziele ohne die Verwendung von DataSets effizient zu erreichen. (Es gibt natürlich auch Anwendungen, wo das DataSet das optimale Mittel ist.)
"

 


Deutschsprachige ALT.NET Homepage

June 24, 2008 22:39 by Jens

Die deutschsprachige ALT.NET Community hat nun neben der Google Group auch eine eigene Webseite. Sie ist unter http://www.altdotnet.de zu erreichen.


ReSharper 4.0 released

June 9, 2008 23:20 by Jens

The great guys from JetBrains finally released ReSharper 4.0. Congratulations for a great work the team has done.

If you are a C# developer and don't know ReSharper make sure to check it out. It will make your life so much easier.


Fancy UI controls considered harmful

June 4, 2008 23:39 by Jens
We are currently working on the very first iteration of our healthcare application. The goal for this iteration is to provide some basic means of navigation and a dashboard-like screen.

I was responsible for the navigation part. It should consist of a list of patients to select from, a menu-like panel to invoke use cases and some other rather minor things. A rather great deal of work has to be done to develop a basic underlying application framework. That doesn't leave much time to tweak the user interface and create nice-looking navigation parts.

My co-worker's task is to create a screen that shows some summary information including a chart to display some health data.
Today he showed me a first draft of the screen. It showed a very pretty chart. With animated lines and gradient colors. A typical WPF chart.

It looked very cool. But I didn't think it was a good idea to include such modern control as part of the first iteration. While all other parts of the app look pretty basic and simple, the chart will draw much of the test users' attention.

But that is not what I want to achieve with the first and very basic iteration drop. The primary aim should be to get as many meaningful feedback as possible. But I'm afraid the test users will get distracted and won't deliver as much support as would be possible.
Don't get me wrong here. This is unconscious behavior. The chart control will catch every tester's eyes. This is not what I want to achieve.

So our strategy is to include a simpler version of the chart first and upgrade its appearance along with all other user interface parts. This way we can make sure that the testers don't focus too much on only one part.
Tags:
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed