ASP.NET: Schichtentrennung – Hilfskomponente
So, auf vielfachen Wunsch: Eine kleine Serie zum Thema Schichtentrennung. Bevor wir aber anfangen können, mit Schichten zu arbeiten, benötigen wir einen Mechanismus, der es uns erlaubt, Komponenten anhand von Konfigurationseinstellungen zu laden. Das nutzen wir später, um diverse Entwurfsmuster brauchbar implementieren zu können.
Damit Komponenten geladen werden können, definieren wir zunächst eine Basisklasse BaseManager. Diese Basisklasse verfügt über eine überschreibbare Methode Init(), die von ableitenden Klassen genutzt werden kann, um sich zu initialisieren. Wir lagern also diese spezielle und individuelle Logik auf die einzelnen nachzuladenden Komponenten aus. Die Nutzung dieser Basisklasse ist jedoch optional – Komponenten sollten sich stets auch laden lassen, ohne das diese Basisklasse erweitert wird:
using System;
namespace de.ksamaschke.tools public abstract class BaseManager public virtual void Init()
{
///
///
{
///
///
{
// Intentionally left blank
}
}
}
Im nächsten Schritt wird der Lademechanismus definiert. Dieser ist wiederverwendbar gestaltet – er sollte also in jedem Kontext funktionieren können. Somit gibt es hier keine festen Verdrahtungen mit irgendwelchen Klassen, sondern die Instanzen werden per Reflection erzeugt.
Wie aber kommen wir an die benötigten Informationen (Klassenname, Assembly-Name)?
Diese liegen in der Konfigurationsdatei der Applikation (je nach Einsatzzweck entweder die web.config oder die app.config für Client-Applikationen). Der Einfachheit halber tragen wir die Typinformationen im appSettings-Bereich ein (in meinen Projekten gibt es hier üblicherweise einen eigenen Konfigurationsbereich je Komponente, aber das würde hier den Rahmen sprengen). Gefunden werden diese Typinformationen über den Typnamen der beim Aufruf der Methode Load() angegebenen Basiskomponente. Damit schlagen wir gleich zwei Fliegen mit einer Klappe: Das Ding wird wiederverwendbar, da ich keine feste Verdrahtung mit irgendwelchen Klassen habe und wir zwingen uns selbst zum so genannten Contract First-Design, bei dem wir zunächst eine Basisklasse und erst später konkrete Implementierungen bereit stellen.
Der Lademechanismus befindet sich in der Klasse ManagerLoader. Hier werden zunächst die Informationen aus der Konfigurationsdatei ausgelesen und anschließend wird versucht, die Komponente zu instanzieren. War dies erfolgreich, wird geprüft, ob die Komponente von der Basisklasse BaseManager erbt und wenn dem so ist, wird die Init()-Methode eingebunden:
using System;
using System.Configuration;
using System.Runtime.Remoting;
namespace de.ksamaschke.tools
{
///
///
public class ManagerLoader
{
///
///
public static T Load
{
// Get the name of the settings-area
string settingsName = typeof(T).Name;
// Get the config-value
string nameAndAssembly =
ConfigurationManager.AppSettings[
settingsName];
// Check the config-value
if (!String.IsNullOrEmpty(nameAndAssembly))
{
// Get the type-name
string typeName =
nameAndAssembly.Substring(0,
nameAndAssembly.IndexOf(“,”));
// Get the assembly-name
string assemblyName =
nameAndAssembly.Substring(
nameAndAssembly.IndexOf(“,”) + 1);
// Try to create an instance
try
{
// Get the instance
ObjectHandle handle =
Activator.CreateInstance(
assemblyName, typeName);
if (null != handle)
{
object result = handle.Unwrap();
// Try to initialize
if (null != result &&
result is BaseManager)
{
((BaseManager)result).Init();
}
if (result is T)
{
return (T) result;
}
}
}
catch
{
// Intentionally left blank
}
}
throw new Exception(
string.Format(
“Unable to load manager for type {0}”,
settingsName));
}
}
}
Um später mit dieser Klasse Komponenten laden zu können, müssen Sie in der Konfigurationsdatei einen Eintrag anlegen, der dieses Format hat:
CustomerManagerImplementation” />
(Ohne den Zeilenumbruch innerhalb des
Damit haben wir die Grundvoraussetzungen geschaffen, um später mit Schichtentrennungen arbeiten zu können. Sie sollten diese Klassen in einem eigenen C#-Projekt ablegen, so dass Sie sie später immer wieder verwenden können.
Comments(3)
Hallo,
danke das Sie sich die Mühe machen uns das Thema zu erklären.
Ich werde auf jeden Fall am Ball bleiben.
Hm…ehrlich gesagt, da hört’s bei mir schon auf. Ich kapiere nicht was diese Klasse machen soll und was sie mit Schichtentrennung zu tun hat.
Und nu?
Fehlt mir essentielles Grundwissen? Muß ich noch ein paar Stufen weiter unten anfangen?
Oder soll ich einfach bis zum ersten “richtigen” Schichtentrennungs-Artikel warten und hoffen daß es dann klarer wird?
Hi haarrrgh,
soweit ich diesen Code verstanden hab hat das jetzt weniger mit der Schichtentrennung zu tun sonder ist ein geniale Art ein Programm richtig in OOP zu schreiben.
Der Sinn dieser Klassen ist, andere Klassen die vom BaseManager erben, automatisch laden zu lassen. Beim Hinzufügen oder Löschen von Klassen muss ich dann nicht in jeder Klasse etwas ändern sonder man braucht dies nur in der web.config / app.config zu tun.
So braucht man dann nicht jede Klasse anfassen wodurch die Wiederverwendbarkeit und Wartbarkeit einfacher wird.
Um so ein Beispiel zu finden habe ich echt schon 2 Wochen lange im Internet ohne erfolg gesucht.
Nochmals danke für dieses Beispiel.