Archive for June, 2009

Über Reflection kann man zur Laufzeit relativ einfach an alle Informationen eines Assembly herankommen. So ist es möglich, dass man von einem Assembly den Namen, Klassen, Methoden mit ihren Parametern, Eigenschaften und Rückgabewerte, usw. auslesen kann. Aber nicht nur das Auslesen ist möglich, sondern auch das Setzen.

Jetzt stellt sich für den einen oder anderen vielleicht die Frage, warum man zur Laufzeit auf diese Daten zugreifen kann. Jede Assembly verfügt über Module in denen sich die einzelnen Typen(Klassen) befinden. Für jedes Modul gibt es Metadaten, in denen die einzelnen Typen beschrieben werden. Die Assembly selbst verfügt noch über ein Manifest, in dem sich alle Informationen zum Assembly (z.B. Name, Version) befinden. Wenn man über Reflection auf Assemblies zugreift, dann werden diese Metadaten und das Manifest dafür herangezogen. Die Metadaten verfügen zwar noch über die Informationen, welche Modifizierer für Methoden, Properties, usw. verwendet wurden, aber der MSIL-Code (die Zwischensprache, die vom Endcompiler in die plattformspezifische Sprache übersetzt wird) nicht mehr. Die Modifizierer sind nur für den Compiler relevant und werden nach dem Kompilieren nicht mehr berücksichtigt. Somit ist es auch möglich über Reflection Properties, Methoden, usw. zu verwenden, die nicht öffentlich sind.

Für dieses Beispiel habe ich eine kleine Konsolen-Anwendung geschrieben (TestApplication), welche eine Referenz auf das Assembly TestProject.dll hat. Dieses Assembly hat zwei von mir erstellte Typen (Klassen) TestClass und SecondTestClass. In den beiden Klassen steckt keine Logik. Sie sind ausschließlich für dieses Beispiel erstellt worden, um ein paar Daten zu modifizieren und um zu zeigen wie die Informationen aus dem Assembly ausgelesen und verändert werden können und dass es möglich ist an nicht-öffentliche Methoden heranzukommen. weiter lesen…

Comments No Comments »

Seit einiger Zeit sind wir dabei, unser Portal zu refaktorisieren. Das entfernte Ziel ist, alles in .NET um zu bauen. Das betrifft zur Zeit über tausend Seiten aber wir möchten noch in diesem Leben fertig sein 😉

Dazu kommt noch, dass wir – selbstverständlich – agiles Softwarentwicklung betreiben, was eine ständige und rhythmische Iteration vorsieht, keine Mega-Projekte mit ungewissem Ende. Also haben wir die verschiedenen Bereiche identifiziert und diese werden einer nach dem anderen neu gebaut.
Die neuen DLL-s in .NET werden mit Hilfe von verschiedenen Webservices angesprochen. weiter lesen …

Comments 11 Comments »

Anonyme Datentypen sind Klassen, die erst beim Kompilieren durch den Compiler definiert werden. Die Klassendefinition befindet sich also nicht im Quellcode. Die anonymen Datentypen leiten wie jedes andere Referenzobjekt von der Klasse object ab. Sie sind als reine Datenklassen gedacht und es können keine weiteren Methoden oder Events hinzugefügt werden. Obwohl der anonyme Datentyp auf Quellcodeebene noch nicht definiert ist, muss dank Visual Studio nicht auf die Intellisense verzichtet werden.

Definiert und intstanziert werden sie mit new und einem Objektinitialisierer:

    var mitarbeiter = new { Name = "Müller", Abteilung = "IT" };

var ist der implizite Typ und nicht der anonyme Datentyp. Er fungiert hier lediglich als container für die Instanz des anonymen Datentyps, die mit new {} erzeugt wird.

Gibt man keinen Namen für die Properties an, werden die Namen der Properties verwendet, mit denen initialisiert wird.

    var abteilung = new { Abteilungsname = "IT" };
    var mitarbeiter = new { Name = "Müller", abteilung.Abteilungsname };
    Console.WriteLine(mitarbeiter.Abteilungsname);

Wenn man mit Werten initialisiert, muss ein Name angegeben werden.

Anonyme Datentypen bieten sich an, wenn man Abfragen mit Linq ausführt und entweder nur eine Teilmenge des ursprünglichen Objekts braucht, oder wenn man ein Objekt erweitern will, ohne extra eine neue Klasse zu definieren.

Hier ein Beispiel aus einem Castle Monorail Projekt, in dem eine erweiterte Liste an eine vm gegeben wird, ohne eine neue Klasse definieren zu müssen. Es soll dabei eine Liste erstellt werden, in der die Mitarbeiter mit ihrem Horoskop verknüpft werden :

    public void Action() {
        IList<Mitarbeiter> mitarbeiterListe = m_service.GetMitarbeiter();
        var mitarbeiterMitHoroskopListe = (from mitarbeiter in mitarbeiterListe
            select new { Mitarbeiter = mitarbeiter,
                         Horoskop = GetHoroskop(mitarbeiter.Geburtsdatum) });
        PropertyBag["mitarbeiterMitHoroskopListe"] = mitarbeiterMitHoroskopListe;
    }

Comments No Comments »

Ich bin gerade auf eine sehr interessante Seite mit einzelnen WebCasts zu .NET Themen aufmerksam geworden.

http://www.dimecasts.net/

Habe mir dort gleich mal “#106 – Learning the Adapter Pattern” angesehen, dort wird sehr schön in nur 9 Minuten erklärt wie man das AdapterPattern einsetzt.

Comments No Comments »

Heute habe ich einen recht interessanten Artikel gelesen. In diesem ging es darum besseren Code zu schreiben, zu warten und im allgemeinen besser mit ihm umzugehen. Die Rede ist dabei von Clean-Code-Developer.

Dabei geht es weder darum neue Technologien zu verwenden, noch darum neue Sprachen zu erlernen. Eigentlich ist es eher ein kleiner Leitfaden um sich stetig zu verbessern, und das wollen wir doch im Allgemeinen eh, sonst würde dieser Blog-Eintrag wohl auch nicht gelesen.

Comments 2 Comments »

Da wir kein geeignetes Plugin für WordPress gefunden haben, um .NET-Code wie in Visual Studio darzustellen, habe ich ein wenig gegooglet und bin auf ein Addin namens “Copy Source As HTML” für Visual Studio 2008 gestoßen. Mit diesem Addin ist es möglich, seinen Sourcecode schön formatiert in HTML umzuwandeln.

Downloadlink und Anleitung findet man hier.

Nach der Installation steht im Kontextmenü neben Copy, Paste usw. auch der Punkt “Copy As HTML…” zur Verfügung. Bevor der umgewandelte Sourcecode in den Zwischenspeicher gespeichert wird, hat man die Möglichkeit, seine Konfiguration anzupassen.

Hierfür habe ich folgende Konfiguration verwendet:

Config

Nach der Bestätigung der Konfiguration sieht das Ergebnis folgendermaßen aus :

 

   12     /// <summary>
   13     /// Summary
   14     /// </summary>
   15     class Program {
   16         static void Main() {
   17             // Kommentar
   18             Console.WriteLine("Hello World");
   19         }
   20     }

Comments 3 Comments »

In diesem Blog-Post möchte ich kurz erläutern, wie ich mit dem Problem des dynamischen Ladens von Assemblies umgegangen bin.

Vor einiger Zeit stand ich vor dem Problem, dass ich zur Laufzeit Assemblies austauschen wollte. Grund dafür war, dass ich eine Host-Applikation hatte, die Plug-Ins verwendet. Jetzt wollte ich bestehende Plug-Ins während der Laufzeit austauschen oder neue Plug-Ins hinzufügen ohne die Host-Applikation zu beenden. Dazu hatte ich ein Verzeichnis in dem sich, außer den Plug-Ins, alle Assemblies befanden. Die Plug-Ins selbst befanden sich in einem eigenen Unterverzeichnis. Selbst wenn die Plug-Ins von der Host-Applikation nicht mehr verwendet wurden, war es nicht möglich, diese Assemblies zu löschen.

Im Normalfall ist es so, dass sobald eine Assembly von einer Applikation verwendet wird, eine Referenz auf diese existiert. Diese Referenz wird leider erst gelöscht, wenn die ganze Applikation beendet wird.

Bei dem dynamischen Laden von Assemblies wird die zu ladende Assembly geöffnet, ausgelesen und dann geschlossen. Aus den ausgelesenen Bytes wird dann mittels Reflection eine Assembly im Arbeitsspeicher erzeugt. Auf die lokale Assembly hängt somit keine Referenz und es ist möglich diese zu löschen.

Meine Umsetzung sieht folgendermaßen aus:

    2 public IList<Plugin> GetPlugins(string assemblyName) {
    3     Assembly assembly;
    4     IList<Plugin> pluginList = new IList<Plugin>();
    5     try {
    6         byte[] byteAssembly = File.ReadAllBytes(assemblyName);
    7         assembly = Assembly.Load(byteAssembly);
    8     } catch (Exception ex) {
    9         log.Error(ex);
   10     }
   11     try {
   12         if (assembly != null) {
   13             Type[] assemblyTypes = assembly.GetTypes();
   14             foreach (Type assemblyTyp in assemblyTypes) {
   15                 if (typeof(Plugin).IsAssignableFrom(assemblyTyp)) {
   16                     plugin = (Plugin)assembly.CreateInstance(assemblyTyp
   17                                                                 .FullName);
   18                     if (plugin != null) {
   19                         pluginList.Add(plugin);
   20                     }
   21                 }
   22             }
   23         }
   24     } catch (ReflectionTypeLoadException ex) {
   25         log.Error(ex);
   26     }
   27     return pluginList;
   28 }

Comments No Comments »

In meinem ersten Blog-Post möchte ich euch in vereinfachter Form meine Umsetzung des Plug-In-Patterns vorstellen.
Voraussetzungen für dieses Pattern sind:

  • eine Host-Applikation die das Plug-In laden möchte
  • ein Plug-In welches es zu laden gilt
  • und die Schnittstellen Plugin und IHost

Zu allererst brauchen wir eine gemeinsame Schnittstelle, die sowohl vom Plug-In als auch vom Host (die Applikation welche das Plug-In verwenden soll) benutzt werden soll. Über diese Schnittstelle kommuniziert der Host mit dem Plug-In.
Es würde sich das Interface IPlugIn anbieten. In meinem Fall verwende ich allerdings kein Interface sondern eine abstrakte Klasse, da ich bereits Logik direkt in die Schnittstelle implementieren möchte. In meinem Fall heißt die abstrakte Klasse einfach nur Plugin. Im weiteren Verlauf werde ich zu meiner abstrakten Klasse Schnittstelle sagen.

    1 public abstract class Plugin {
    2     private IHost m_host;
    3     public Plugin(string name) {
    4         Name = name;
    5     }
    6
    7     public string Name { get; set; }
    8     public string Author { get; set; }
    9     public string Version { get; set; }
   10     public bool IsRegistered { get; private set; }
   11
   12     /// <summary>
   13     /// Setzt oder gibt die Host-Application.
   14     /// </summary>
   15     /// <value>Host-Application.</value>
   16     public IHost Host {
   17         get { return m_host; }
   18         set {
   19             if (value != null) {
   20                 if (m_host == null) {
   21                     m_host = value;
   22                     if (m_host.Register(this)) {
   23                         IsRegistered = true;
   24                     }
   25                 }
   26             } else {
   27                 if (m_host.Unregister(this)) {
   28                     m_host = value;
   29                     IsRegistered = false;
   30                 }
   31             }
   32         }
   33     }
   34 }

Ich glaube, der Aufbau der Schnittstelle Plugin sollte bis auf die Property “Host” klar sein. Wie man sieht, benötigt man bei diesem Pattern zusätzlich zur Schnittstelle Plugin noch das IHost-Interface.
Dieses Interface ist direkter Bestandteil der Schnittstelle Plugin. Nun kann man sich natürlich die Frage stellen, warum das Plug-In den Host kennen muss und somit von diesem abhängig ist.

Zum einen ist es in der Regel so, dass ein Plug-In für nur einen Host entwickelt wird und zum anderen wollte ich dem Host gewisse Richtlinien zum Registrieren und Lösen des Plug-Ins vorgeben.

Das Interface IHost sieht folgendermaßen aus:

    1 public interface IHost {
    2     bool Register(Plugin plugin);
    3     bool Unregister(Plugin plugin);
    4 }

Dieses Interface muss von der Host-Applikation implementiert werden, damit sich das Plug-In am Host registrieren kann. Im letzten Satz habe ich es schon angedeutet. Nicht der Host registriert das Plug-In bei sich, sondern das Plug-In registriert sich am Host. Durch das setzen der Property Plugin.Host wird die Methode Register oder Unregister vom Plug-In aufgerufen, welche der Host implementiert.

Eine vereinfachte Darstellung der Implementierung des IHost -Interfaces sieht folgendermaßen aus:

    1 public class HostApplication : IHost {
    2     private List<Plugin> m_pluginList;
    3
    4     //Konstruktor
    5     public HostApplication() {
    6         m_pluginList = new List<Plugin>();
    7
    8         //Lädt alle verfügbaren Plug-Ins zb. aus einem Verzeichnis
    9         List<Plugin> plugins = GetPlugins();
   10         foreach (Plugin plugin in plugins) {
   11             //ruft implizit die IHost.Register-Methode auf
   12             plugin.Host = this;
   13         }
   14     }
   15
   16     public void ShowPlugins() {
   17         foreach (Plugin plugin in m_pluginList) {
   18             //Ausgabe der Namen aller am Host registrierten Plug-Ins
   19             Console.WriteLine(plugin.Name);
   20         }
   21     }
   22
   23     public void UnloadPlugins() {
   24         foreach (Plugin plugin in m_pluginList) {
   25             //ruft implizit die IHost.Unregister-Methode auf
   26             plugin.Host = null;
   27         }
   28     }
   29
   30     #region IHost-Implementierung
   31     public bool Register(Plugin plugin) {
   32         if (!m_pluginList.Contains(plugin)) {
   33             m_pluginList.Add(plugin);
   34             return true;
   35         }
   36         return false;
   37     }
   38
   39     public bool Unregister(Plugin plugin) {
   40         if (m_pluginList.Contains(plugin)) {
   41             m_pluginList.Remove(plugin);
   42             return true;
   43         }
   44         return false;
   45     }
   46     #endregion
   47 }

Das Registrieren und Lösen der Plug-Ins könnte man nun noch in einen Plug-In-Manager auslagern, worauf ich in diesem Blog allerdings verzichten möchte.

Comments No Comments »