Archive for the ‘.Net’ Category
Ein Einfaches Addin Framework
Seit kurzem beschäftige ich mich etwas mit Reflection und möchte euch helfen ein paar Fehler zu vermeiden welche ich am Anfang gemacht habe. Darum werde ich ein Einfaches Addin Modul erstellen, welches es ermöglicht Addins dynamisch in eine Applikation zu laden.
Der Code
Es werden Mehrere Klassen in unterschiedlichen Assembly’s benötigt um die Funktionsweiße zu demonstrieren. Ich Fange mit den Zentralen Klassen des Frameworks an.
Das Loader Assembly
Wir benötigen ein Attribut welches uns mitteilt welche Klassen ein Addin sind, dazu definieren wir folgende Klasse:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace org.wirsin.blogs.addinframework
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class AddinIdentifier : Attribute
{
private string className;
public string ClassName
{
get
{
return className;
}
private set
{
className = value;
}
}
public AddinIdentifier(string className)
{
this.className = className;
}
}
}
Desweiteren benötigen wir eine Klasse welche das erzeugen einer neuen Addin Instanz übernehmen kann, und unter Umständen auch noch zusätzliche Informationen über die Addins zur Verfügung stellen kann. Diese Informationen sollten über Attribute zur Verfügung gestellt werden. Diese Klasse ist Generisch da wir ja wenn wir uns eine Instanz des Addins erzeugen lassen das Addin Interface als Rückgabewert erwarten.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace org.wirsin.blogs.addinframework
{
public class Addin
{
private Type addinType;
public Addin(Type addinType)
{
this.addinType = addinType;
}
public AddinType Instance
{
get
{
return (AddinType)Activator.CreateInstance(addinType);
}
}
}
}
Die letzte Klasse welche im AddinFramework Assembly beheimatet ist ist der AddinLoader. Diese Klasse dient dazu Addins aus Assembly’s zu laden. Dies ist der “langsamste” Teil des Ladens da jäh nach Vorgehensweise mehrere Typen geladen werden müssen welche unter umständen später nicht mehr verwendet werden. Darum wurde für dieses Beispiel der Ansatz mit Assembly Attributen gewählt. Die Implementation sieht wie folgt aus:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace org.wirsin.blogs.addinframework
{
public class AddinLoader where PluginIdentifier : AddinIdentifier
{
private Type pluginIdentifier;
private Type pluginType;
private List> addins = new List>();
public List> Addins
{
get
{
return addins;
}
private set
{
addins = value;
}
}
public AddinLoader()
{
pluginIdentifier = typeof(PluginIdentifier);
pluginType = typeof(PluginType);
}
public void LoadAddinsFromFile(string fileName)
{
Assembly currentAssembly = Assembly.LoadFrom(fileName);
LoadAddinsFromAssembly(currentAssembly);
}
public void LoadAddinsFromAssembly(Assembly assembly)
{
PluginIdentifier[] Attributes = (PluginIdentifier[])assembly.GetCustomAttributes(pluginIdentifier, false);
foreach (PluginIdentifier i in Attributes)
{
addins.Add(new Addin(assembly.GetType(i.ClassName)));
}
}
}
}
Diese Klasse ist wiederum Generisch definiert. Dadurch ist es Möglich Addins zu laden welche nicht ausschließlich mittels des in diesem Assembly definierten AddinIdentifier geladen werden können sondern mittels Attributen versehen werden können welche von AddinIdentifier erben. Die Zentrale Methode und gleichzeitig auch die Methode mit dem höchsten Einsparungs potential ist die LoadAddinsFromAssembly Methode. Durch die Implementierung die gewählt wurde sind Teilweise riesige Einsparungsmöglichkeiten gegeben. Man könnte diese Methode auch Implementieren indem man jeden Typ im Assembly daraufhin überprüft ob er z.B.: ein spezielles Interface implementiert oder ob die Klasse mit einem Speziellen Attribut gekennzeichnet ist. Dies können in großen Assemblies mehrere Hundert Iterationen sein um festzustellen das nur ein Addin im Assembly definiert ist. Mit der hier implementieren Methode werden wirklich nur diese Typen aus dem Assembly geladen welche als Addin dienen.
Der Client
In unserer Implementierung ist der Client eine einfache Konsolen Application welche Addins verwendet um beliebigen Inhalt auf die Console zu schreiben.
Als erstes benötigen wir ein Interface welches ein Addin repräsentiert.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace org.wirsin.blogs.addinframework
{
public interface IAddin
{
void WriteSomething();
}
}
Und den Client welcher die AddinLoader Klasse verwendet um Addins aus einem Anderen Assembly nachzuladen.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace org.wirsin.blogs.addinframework
{
class Program
{
static void Main(string[] args)
{
AddinLoader loader = new AddinLoader();
loader.LoadAddinsFromFile("Addins.dll");
foreach (Addin i in loader.Addins)
{
i.Instance.WriteSomething();
}
Console.ReadLine();
}
}
}
Die Addins
Alle Addins werden in einem Assembly definiert. Diese Definition kann auch gerne in mehreren Addins erfolgen. Die Iteration über den AddinFolder muss dann aber vom Client durchgeführt werden.
Nun zur Implementierung, In diesem Assembly benötigen wir eine Reference auf die Client Application und auf das AddinFramework Assembly. Wenn die Referenzen gesetzt sind implementieren wir folgende Klassen.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
[assembly: org.wirsin.blogs.addinframework.AddinIdentifier("org.wirsin.blogs.addinframework.FirstAddin")]
namespace org.wirsin.blogs.addinframework
{
public class FirstAddin : IAddin
{
#region IAddin Members
public void WriteSomething()
{
Console.WriteLine("FirstAddin Loaded.");
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
[assembly: org.wirsin.blogs.addinframework.AddinIdentifier("org.wirsin.blogs.addinframework.SecondAddin")]
namespace org.wirsin.blogs.addinframework
{
public class SecondAddin : IAddin
{
#region IAddin Members
public void WriteSomething()
{
Console.WriteLine("SecondAddin loaded");
}
#endregion
}
}
Beide Addins Implementieren das IAddin Interface und werden mittels eines Assembly Attribute als Addin Identifiziert.
Die Demo
Der Output des Clients sieht wie folgt aus. Auf die Reihenfolge in welcher die AddIns ausgeführt werden nehmen wir keinen Einfluss.

Demo Application für den AddinLoader
Solltet ihr noch fragen haben schreibt einfach einen Kommentar und lasst es mich wissen.
You are currently browsing the archives for the .Net category.