HowTo: Erste Schritte mit dem MEF (Hello MEF!)

In fast jeder Applikation kann man Plugins hinzufügen. In .NET 4.0 kommt eine neue Möglichkeit hinzu die man heute bereits ausprobieren kann. Die Rede ist von dem "Managed Extensibility Framework" – kurz MEF.
MEF soll auch in Visual Studio 2010 selbst einzughalten (siehe PDC Keynote von Scott Guthrie). Dazu kann ich auch die PDC Session von Scott Hanselman über sein "BabySmash" empfehlen.

Addins? Gab es da nicht schonmal was?
Es gibt seit .NET 3.5 einen "System.AddIn" Namensraum. Meiner Meinung nach war es relativ kompliziert Addins zu entwickeln. Allerdings soll MEF und System.Addin gut zusammenarbeiten.

Was braucht man?
Alles was man braucht findet man auf der Codeplex Seite. Einfach den neusten Release runterladen und die 2 DLLs in eigene Projekte einsetzen (Achtung – es befindet sich noch in Entwicklung und kann sich jederzeit ändern).

Hello World! Hallo Welt! Hello MEF! – Vorbereitung

Projektstruktur:

image

Wir haben einen einfachen Serviceinterface namens "IHelloService":

    public interface IHelloService
    {
        string GetHelloMessage();
    }

In dem HelloMEF.English / German Projekt haben wir folgenden Code (hier für das englische Plugin) :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HelloMEF.App;
using System.ComponentModel.Composition;

namespace HelloMEF.English
{
    [Export(typeof(IHelloService))]
    public class EnglishHelloService : IHelloService
    {
        public string GetHelloMessage()
        {
            return "Hello World!";
        }
    }
}

Wichtig hier ist das "Export" Attribut aus dem "System.ComponentModel.Composite" (MEF) Namespace.

Damit wird ausgedrückt: Dies ist ein Plugin des Typs IHelloService.

In diesen beiden Projekten kann man machen was man möchte. Hier muss man nur die Referenz auf die HelloMEF.App wegen des Interfaces machen. Ansonsten kennen sich die Applikationen nicht!

Plugin Ordner

Damit die Applikation überhaupt die beiden Plugins kennt, werfen wir beide DLLs in einen eigenen Ordner namens "PlugIns":

image

HelloMEF.App – HelloProgram:

    public class HelloProgram
    {
        [Import(typeof(IHelloService))]
        public List<IHelloService> Services { get; set; }

        public HelloProgram()
        {
	...
        }

        public void WriteHelloGreetings()
        {
            Console.WriteLine();
            Console.WriteLine("Writing Greetings...");

            foreach (IHelloService srv in Services)
            {
                Console.WriteLine(srv.GetHelloMessage());
            }

            Console.WriteLine("... powered by MEF");
        }
    }

In der "HelloProgram" Klasse haben wir eine Liste an "IHelloServices", welches mit dem "Import" Attribute aus dem MEF Namensraum dekoriert ist.

Das bedeutet: Ich nehme alles vom Typen IHelloService auf.

In unserer Ausgabe iterieren wir einfach über diese Liste und rufen die GetHelloMessage auf.

HelloMEF.App – Plugins suchen und finden:

        public HelloProgram()
        {
            this.Services = new List<IHelloService>();

            if (!Directory.Exists("PlugIns"))
            {
                Directory.CreateDirectory("PlugIns");
            }

            AggregatingComposablePartCatalog catalog = new AggregatingComposablePartCatalog();
            catalog.Catalogs.Add(new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
            catalog.Catalogs.Add(new DirectoryPartCatalog("PlugIns"));

            CompositionContainer container = new CompositionContainer(catalog.CreateResolver());
            container.AddPart(this);
            container.Compose();
        }

Wir schauen erstmal nach dem "PluginIns" Verzeichnis und erstellen es wenn nötig. Jetzt folgt pure MEF-Action.

Die PlugIns werden in Katalogen verwaltet. Unserem Katalog sagen wir hier, dass es nach Plugins in dieser Assembly suchen soll:

            catalog.Catalogs.Add(new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));

Und das es auch ein Verzeichnis überwachen soll:

            catalog.Catalogs.Add(new DirectoryPartCatalog("PlugIns"));

Es gibt auch die Möglichkeit das Verzeichnis überwachen zu lassen, sodass man zur Laufzeit Plugins hinzufügen könnte:

image

Durch den Container sagen wir MEF, dass wir hier eine Pluginschnittstelle haben (die Liste mit dem "Import" Attribut) und am Ende geben wir den "Compose" Befehl.

HelloMEF.App – Plugins in derselben Assembly:

namespace HelloMEF.App
{
    public class HelloProgram
    {
	...
    }

    [Export(typeof(IHelloService))]
    public class MEFHelloService : IHelloService
    {
	...
    }

}

Die Plugins können auch in derselben Assembly stehen, MEF findet es durch den "AttributeAssemblyPartCatalog" ebenfalls.

Das Ergebnis:

image

 [ Download Source Code ]


Kick It auf dotnet-kicks.de
Wenn dir der Blogpost gefallen hat, dann hinterlasse doch einen Kommentar. Wenn du auf dem Laufenden bleiben willst, abonniere unseren RSS Feed oder folge uns auf Twitter.

About the author

Written by Robert Mühsig

Robert Mühsig (@robert0muehsig) ist Webentwickler und beschäftigt sich mit Web-Frameworks (vor allem dem ASP.NET MVC Framework) und scheut sich auch nicht vor Javascript. Ansonsten bloggt er über all jene Probleme, die ihm über den Weg laufen. Seit 2008 ist er Microsoft MVP für ASP.NET und er arbeitet bei der T-Systems Multimedia Solutions GmbH in Dresden. Treffen kann man ihn online via Twitter (@robert0muehsig) oder dieser Seite oder bei der .NET User Group Dresden.

2 Responses

  1. Hallo,

    ich habe Probleme, das simple Beispiel geht, aber wenn ich zwei Interfaces in einer Assembly definiere, dann eine Klasse schreibe, die die beiden Interfaces implementiert und Exportiert, und in der anderen Assembly mit einem DirectoryPartCatalog arbeite, findet er nichts zusammen …..

    Auf welcher Leitung stehe ich da?

    DANKE

    Gruß

    Gerhard

    Reply
  2. ??????????????????????????????????????????

    Wer hat jetzt die korrekte Version. Auf meiner verzweifelten Suche nach einer Lösung fand ich folgendes Beispiel:

    1 public class Program
    2 {
    3 static void Main(string[] args)
    4 {
    5 var consumer = new Consumer(); // Objekt mit Imports
    6
    7 var catalog = new AssemblyComponentCatalog();
    8 catalog.AddAssembly(Assembly.GetExecutingAssembly());
    9
    10 var container = new CompositionContainer(catalog.Resolver);
    11 container.AddComponent(consumer);
    12 container.Bind(); // lost die Imports von consumer auf
    13
    14 consumer.ShoutMessage();
    15 }
    16 }

    Sorry, aber ‘mein’ Container versteht weder AddComponent noch Bind.

    Bin ich überhaupt im flaschen Film???

    HILFEEEEE

    Ich habe jedenfalls den Code von Codeplex geladen und referenziere auch die passende dll, also jene, die mir auf Codeplex als die aktuelle ‘verkauft’ wurde.
    Das habe ich ausführlich und mehrmals überprüft, um nicht Opfer irgend einer Trivialität zu werden ….

    Gruß

    Gerhard

    Reply

Comment on this post

Letzte Posts

  • image.png
    Chocolatey–apt-get für Windows

    Durch Zufall bin ich auf das Tool “Chocolatey” gestoßen. Wer die Website sich anschaut, wird evtl. eine Verwandschaft mit NuGet ausmachen. Was macht Chocolatey? Chocolatey ist ein “Maschine Package Manager”, das bedeutet, dass man für seine Maschine einfach Tools runterladen und Updaten kann – direkt über die Konsole. Was ist der Unterschied zu NuGet? NuGet ...

  • image.png
    SASS, LESS & Coffeescript in Visual Studio mit der Web Workbench

    CSS und Javascript sind die “kleinste” Schnittmenge von allen Browsern für die Erstellung von Web-Applikationen. Leider geht dabei etwas komfort verloren, daher lieben alle Webentwickler jQuery! SASS und LESS sind zwei Varianten, wie man “schöner” CSS schreiben kann und Coffeescript versucht Javascript Entwicklung zu vereinfachen. Aber immer der Reihe nach… Was ist SASS? SASS steht ...

  • image.png
    Code-Inside Sample nun auf GitHub: Google Code zu GitHub Migration

    Seit einiger Zeit habe ich Beispielcode auf Google Code bereitgestellt. Einfach nur noch weg von Google Code O-Ton damals war: Ich hatte mich für Google Code entschieden, weil ich hoffe dass früher oder später die Google Code Suche nutzbar ist und es dadurch wenigstens ein kleiner Mehrwert entsteht. Allerdings wirft es momentan noch ein Fehler. ...

  • image.png
    Windows-8-Hackathon @Night in Leipzig

    Hacken (=Entwickeln, nichts böswilliges!), Grillen und mitten in der Nacht fachsimpeln? Dann ist vielleicht der Windows-8-Hackathon was für dich. Der Hackathon wird vom 15. Juni (ab 19:00) bis zum 16. Juni (bis in die frühen Morgenstunden) in Leipzig stattfinden.  Mit dabei sind auch Darius Parys und Tom Wendel von der Microsoft Deutschland. Thematisch (wie der ...

  • image.png
    Einstieg in Redis on Windows & Redis mit .NET benutzen

    Redis gehört zu den NoSQL Datenbanken und ist dort in der Familie der Key-Value Stores zu finden. Redis wird oft mit “Blazing Fast” betitelt und laut dem Stackoverflow Thread soll es im Vergleich zu MongoDB zweimal (beim Schreiben) und sogar dreimal (beim Lesen) so schnell sein wie MongoDB – auch wenn der Vergleich etwas “hinkt” ...

Auf Amazon einkaufen & unterstützen

Facebook