Fremdschlüssel in SQL Azure- Quick Hint [experimental]

Bei der Erstellung einer Datenbank in SQL Azure bietet die Verwaltungsoberfläche die Erstellung von Datenbanktabellen. Die Herstellung einer Fremdschlüsselbeziehung ist in der Silverlight- GUI noch nicht integriert.

Für das modellieren eines kompletten Datenmodells in SQL Azure ist es daher sinnvoll das SQL ManagementStudio 2008 R2 zu verwenden.
Für Experimente ist es allerdings möglich den Fremdschlüssel über typische SQL Statements zu definieren.

create SQL Query

Das oben stehende Bild zeigt, dass in der Verwaltungsoberfläche von SQL Azure eine neue “Query”, zu deutsch: eine neue Abfrage, direkt im Browser erstellt werden kann.
Folgende Vorlage erzeugt eine Fremdschlüsselbeziehung:
[sourcecode language=”sql”]
ALTER TABLE [dbo].[Fremdschlüssel_Tabelle] 
WITH CHECK ADD  CONSTRAINT [Name_der_Fremdschlüsselbezieunh]
FOREIGN KEY([Name_des_Fremdschlüsselfelds])
REFERENCES [dbo].[Primärschlüssel_Tabelle] ([Name_des_Primärschlüsselfelds])
GO
[/sourcecode]

Für das Arbeiten und Experimentieren für unterwegs eine feine Sache.

Frohes Programmieren!
Gregor

Eine erste Anwendung mit Prism 4

[Download zum Post: PrismBeginnersSample.zip ]

Ende November ist die neue Version der Prism Library veröffentlicht worden, mit der es möglich ist voneinander entkoppelte Anwendungsmodule zu entwickeln, um diese dann in einer “Root- Shell” zu hosten und darzustellen.

Dieser Ansatz ist als UI- Composition bekannt.

Um eine Anwendung mit Prism zu entwickeln müssen vier Bestandteile behandelt werden.

  • Shell
  • Bootstrapper
  • Modul
  • Modulkatalog

Im folgenden werden die genannten Begriffe näher betrachtet. Dazu legen wir ein Projekt im Visual Studio an und erzeugen eine Silverlight Application mit dem Namen PrismBeginnersSample.

Die Shell

Die Shell ist die Oberfläche in der später alle Anwendungsmodule dargestellt werden. Sie wird mit dem Laden der Anwendung  durch einen Bootstrapper gestartet und angezeigt. Um sie zu erstellen löschen wir als erstes die MainPage.xaml

deleteGeneratedMainPageXaml
MainPage.xml entfernen

Danach wird dem Projekt eine neue Silverlight Page hinzugefügt [STRG + SHIFT + A]. Diese Page nennen wir Shell.xaml, in deren XAML- Code eine Region angelegt werden muss, in die ein Modul geladen werden kann.

Hinweis
Für das Anlegen von Regionen in einer Shell muss die Bibliothek Microsoft.Practices.Prism im Projekt referenziert werden.prism_reference

In der Shell.xaml wird nun ein ContentControl angelegt. Der Namespace von Microsoft.Practises.Prism muss im XAML- Code referenziert werden (Zeile 10 und 11). Danach steht eine Attached Property zur Verfügung, mit der Controls als “Regions” deklariert werden können (Zeile 16).

  1. <navigation:Page x:Class="PrismBeginnersSample.Shell"
  2.           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5.           xmlns:mc="http://schemas.openxmlformats.org/markup-
  6.                     compatibility/2006"
  7.           mc:Ignorable="d"
  8.           xmlns:navigation="clr-namespace:System.Windows.Controls;
  9.                             assembly=System.Windows.Controls.Navigation"
  10.           xmlns:Regions="clr-namespace:Microsoft.Practices.Prism.Regions;
  11.                          assembly=Microsoft.Practices.Prism"
  12.           d:DesignWidth="640" d:DesignHeight="480"
  13.           Title="Shell Page">
  14.     <Grid x:Name="LayoutRoot">
  15.         <ContentControl
  16.            Regions:RegionManager.RegionName="ContentRegion" />
  17.     </Grid>
  18. </navigation:Page>
  19. XAML- Code der Shell

Der Bootstrapper

Die erzeugte Shell wird von einem Bootstrapper gestartet. Also muss eine Klasse für den Bootstrapper angelegt werden.

addedBootstrapper
Anlegen des Bootstrappers.

Hinweis
Für das Anlegen des Bootsrappers müssen die Bibliothekem Microsoft.Practices.Prism und Microsoft.Practices.Unity.Silverlight im Projekt referenziert werden.
prism_reference dll_Unity.silverlight

Der Bootstrapper erbt von Prisms UnityBootstrapper. Nun müssen zwei Methoden überschrieben werden, um die Shell zu starten:

  • CreateShell()
  • InitializeShell()

  1. using System.Windows;
  2. using Microsoft.Practices.Prism.UnityExtensions;
  3. using Microsoft.Practices.Unity;
  4.  
  5. namespace PrismBeginnersSample
  6. {
  7.     public class Bootstrapper : UnityBootstrapper
  8.     {
  9.         protected override DependencyObject CreateShell()
  10.         {
  11.             return Container.Resolve<Shell>();
  12.         }
  13.  
  14.         protected override void InitializeShell()
  15.         {
  16.             base.InitializeShell();
  17.  
  18.             Application.Current.RootVisual = (UIElement) this.Shell;
  19.         }
  20.     }
  21. }

Die Methode CreateShell gibt eine Instanz der angelegten Shell zurück. Die Instanz wird über den UnityContainer aufgelöst (Zeile 11) und als Member Property im Bootstrapper gespeichert. Bei der Initialisierung der Shell setzen wir sie als Startseite unserer Silverlight Anwendung.

Das erste Modul

Das Modul für diese Anwendung wird in einer eigenen Klassenbibliothek realisiert. Hier wird sie PrismContentModule genannt.

Hinweis
Für das Modul in diesem Beispiel wird die Bibliothek Microsoft.Practices.Prism benötigt.

prism_reference

prismcontentmodule

Projektmappe des PrismContentModules

Die gezeigte Silverlight Klassenbibliothek wird mit dem MVVM- Pattern implementiert. Um das Modul an die Shell zu binden ,ist die Klasse Module (Hier im Namespace ModuleDefinitions) ausschlaggebend.

  1. using Microsoft.Practices.Prism.Modularity;
  2. using Microsoft.Practices.Prism.Regions;
  3. using PrismContentModule.Views;
  4.  
  5. namespace PrismContentModule.ModuleDefinitions
  6. {
  7.     public class Module : IModule
  8.     {
  9.         private readonly IRegionManager _regionManager;
  10.  
  11.         public Module(IRegionManager regionManager)
  12.         {
  13.             _regionManager = regionManager;
  14.         }
  15.  
  16.         public void Initialize()
  17.         {
  18.             _regionManager.RegisterViewWithRegion
  19.                 ("ContentRegion", typeof (ContentView));
  20.         }
  21.     }
  22. }

Die Klasse Module erbt von IModule, welches die Implementierung der Methode Initialize() erfordert. In dieser Methode kann ein Modul an einer Region der Shell registriert werden (Zeile 18) . Nötig für die Registrierung sind der Name der “Shell- Region” und der Typ der View, in unserem Beispiel die ContentView.

Für Relation zwischen Shell und Modul ist der IRegionManager zuständig, der mittels ConstructorInjection vom UnityContainer bereitgestellt wird (Zeile 11).

Die View und das View Model des PrismContentModules sind sehr einfach gehalten. Die View enthält lediglich einen Textblock, die an eine String- Property des View Models gebunden wurde.

Damit das Modul in der Silverlightanwendung angezeigt werden kann, muss es nun noch im Modulkatalog referenziert werden.

Der Modulkatalog

Um Module ein Modul in der Shell darzustellen muss sich das Modul an einem Modulkatalog registrieren, der durch den UnityBootstrapper bereits bereitgestellt wird. Dafür wird im Bootstrapper eine weitere Methode überschrieben:

  • CreateModuleCatalog()
  1. protected override IModuleCatalog CreateModuleCatalog()
  2. {
  3.     Type moduleType = typeof (Module);
  4.  
  5.     IModuleCatalog catalog = new ModuleCatalog();
  6.  
  7.     catalog.AddModule(
  8.             new ModuleInfo()
  9.             {
  10.                 ModuleName = moduleType.FullName,
  11.                 ModuleType = moduleType.AssemblyQualifiedName
  12.             });
  13.  
  14.     return catalog;
  15. }
  16.  

In Zeile 3 wird der eine Typ- Variable definiert. Sie enthält den Typen unserer Modul Assembly. In Zeile 5 wird ein neuer Modulkatalog initialisiert. Mit der Methode AddModule kann ein neues Modul hinzugefügt werden. Dazu können beliebig viele Instanzen von ModulInfo erzeugt werden.

Hinweis
Die Module wurden müssen nicht im Code deklariert werden. Sie können auch…

  • in einem XAML- Katalog,
  • in einer Konfigurationsdatei (WPF)
    … gespeichert, oder aber…
  • aus einem spezifizierten Ordner (WPF)
    …geladen werden.
  • Nach dem Starten der Anwendung wird das Modul in der Shell dargestellt.

    fertigeSolution

    Workflow

    Zur Erläuterung der Instanziierung des Moduls über den Bootstrapper wird der Ablauf hier kurz skizziert.

    Initialisierung_Prism_Anwendung

    Übersicht einer Prism- Anwendung

    Um eine Anwendung mit Prism zu entwickeln soll hier ein kurzer Überblick über die Anwendungsarchitektur gegeben werden.

    image
    "Schichtenmodell" einer Prism- Anwendung

    Die Darstellung zeigt, dass eine Shell durch einen Bootstrapper gestartet wird. Der Bootstrapper dient zur Konfiguration der Anwendung und erbt von der Klasse UnityBootstrapper, die durch Prism bereitgestellt wird. Die Shell ist die “Schablone” einer jeden Prism Anwendung, in der unterschiedliche Programmteile dargestellt werden. Die einzelnen Teile werden zur Laufzeit und nicht zur Compilezeit in die Anwendung geladen und werden Module genannt. Die Darstellung zeigt, dass in der Regel jedes Modul mit MVVM implementiert wird. Dies dient der klaren Trennung von Geschäftslogik, Datenschicht und Oberflächengestaltung. Jedes Modul ist selbstständig lauffähig und registriert sich an einem Modulkatalog, dessen Funktionsweise ich in einem vorangegangenen Post erläutert habe. Der Modulkatalog wird über den Unity Container bereitgestellt, der alle Dienste und Klassen verwaltet, die von Modulen verwendet werden können. Beispielsweise kann das die Bereitstellung des Entity Frameworks (EF)sein.

    Mit diesen Grundkenntnissen ist es möglich eine Anwendung in Prism zu entwickeln.

    Das Handwerk Teil 3 – Auch Module verstehen sich!- Event Aggregation

    Vorkenntnisse nötig: Handwerk Teil 2 – Weitere Entkopplung mittels Modularisierung

    Bevor das erworbene wissen über die Prism Bibliotheken in einer WPF- oder Silverlight zum Einsatz kommen kann, muss ein weiteres wichtiges Thema zunächst besprochen werden. In vielen Anwendungen wie in Email Clients (Beispiel: Outlook) kommunizieren die Anwendungsteile miteinander. Wenn eine neue Mail im Posteingang liegt, wird der Posteingang in der Menüliste fettgedruckt und mit der Anzahl nicht gelesener Emails versehen. Dieses Szenario kann mittel Event Aggregation realisiert werden. Doch bevor wir uns einer so komplexen Aufgabe widmen können, müssen die Grundlagen geklärt werden.

    Für Event Aggregation, muss allerdings kein neues Wissen erworben werden, da das Funktionsprinzip in dieser Arbeit bereits im Kapitel „3.4.1 Das Observer Pattern – Wenn Code kommuniziert“ besprochen wurde. In der Anwendung wird eine Instanz des Event Aggregators erzeugt, auf die jedes Modul zugreifen kann. Das Modul wird also zum Observer und registriert jede Änderung im Eventaggregator. Dieser besitzt die Eigenschaften Ereignisse, also Events, zu speichern und wieder zu löschen. Ein Modul kann ein oder mehrere Events abonnieren und selbst veröffentlichen.

    clip_image002
    Kommunikation mittels Event Aggregator

    Der Einsatz des EventAggregators ist denkbar einfach. Dazu muss als erst die Usingdirektive für den entsprechenden Namensraum gesetzt werden.

    [sourcecode language=”csharp”]
    using Microsoft.Practices.Composite.Events;
    [/sourcecode]

    Namensraum in dem Event Aggregator zu finden ist.

    [sourcecode language=”csharp”] EventAggregator eventAggregator = new EventAggregator(); container.RegisterInstance(eventAggregator); [/sourcecode]

    Das Erzeugen einer Instanz des Event Aggregators im Unity Container.

    Nun kann diese Instanz in jedem Modul per Dependency Injection verwendet werden. Als Beispiel veröffentlicht der SimpleTextService ein Ereignis, sobald dessen Methode GetText() verwendet wurde. Diese Event abonniert der OutputService und schreibt eine Nachricht auf die Konsole das der TextService verwendet wurde. Beide Services bekommen den EventAggregator per Constructor Injection übermittelt.

    [sourcecode language=”csharp”]
    private IEventAggregator _aggregator;

    public SimpleTextService(IEventAggregator aggregator)
    {
    _aggregator = aggregator;
    }
    [/sourcecode]

    Übergabe des Event Aggregators an einen Service.

    Wenn der SimpleTextService nun ein Event veröffentlich will muss vorher ein Eventtyp definiert werden. Dafür bietet es sich an, ein separates Projekt anzulegen, das alle Eventtypen enthält. Die Klasses des Events erbt von dem CompositePresentationEvent<T>. Das mysteriöse <T> ist ein. Platzhalte für einen beliebigen Typ, der über das Event transportiert werden soll. Das kann eine Variable vom Typ String- oder ein komplexes Objekt sein.

    [sourcecode language=”csharp”]
    using Microsoft.Practices.Composite.Presentation.Events;

    namespace Infrastructure
    {
    public class ModuleIdentifierEvent :
    CompositePresentationEvent
    {
    }
    }

    [/sourcecode]

    Die Deklaration eines eigenen Eventtyps.

    Wir können also nun ein Event mit der Bezeichnung ModuleIdentifierEvent veröffentlichen und abonnieren. Wir können darüber eine Textnachricht zur weiteren Verarbeitung an ein anderes Modul senden.

    Nachstehend sind die Listings aufgeführt, die zeigen wie das Event vom SimpleTextService veröffentlicht und von ConsoleOutputService abonniert wird.

    [sourcecode language=”csharp”]
    public string GetText()
    {
    _aggregator.GetEvent()
    .Publish("GetText() runs!");
    return "Alles in bester Ordnung!";
    }
    [/sourcecode]

    Veröffentlichen eines Events.

    [sourcecode language=”csharp”]
    public ConsoleOutputService(IEventAggregator aggregator)
    {
    aggregator.GetEvent().
    Subscribe(WriteMessage);
    }
    [/sourcecode]

    Abonnieren des Events im ConsoleOutputService.

    Im Klartext bedeutet das, dass jedes Mal, wenn der SimpleTextService die GetText- Methode ausführt, eine Nachricht auf der Konsole erscheint.

    In der Beispielanwendung gibt es eine Ausgabe auf der Konsole und eine in einem Ausgabefenster. Also gibt es auch zwei Benachrichtigungen über den Ruf der GetText– Methode.

    clip_image002[5]

    Zwei Module kommunizieren über Event Aggregation.

    Nun sind alle Werkzeuge bekannt und jeweils ein Mal angewendet worden. Im nächsten Schritt lösen wir uns von der Konsole und beginnen eine WPF- Anwendung zu schreiben.

    Download der Anwendung zu diesem Beitrag:

    T_EventAggregatorUnityApplication.zip

    Handwerk Teil 2 – Weitere Entkopplung mittels Modularisierung

    nötige Vorkenntnisse:  Das Handwerk Teil 1 – Dependency Injection

    Wir sind dank Dependency Injection in der Lage die Logik einer Anwendung zur Laufzeit zu instanziieren und somit die Abhängigkeit zum Programm selbst zu lösen. Nun gehen wir einen entscheidenden Schritt weiter und verlagern die Konfiguration des Containers. Die Anwendung hat nun weder Kenntnis welche Implementierung der Interfaces sie nutzen wird, noch über die Interfaces selbst.

    Nun sollen Module in die Anwendung eingebracht werden, die entscheiden wie sie den Unity Container konfigurieren. Das Programm bietet sich lediglich als Plattform an, in der mehrere Module existieren, die eine beliebige Funktion ausführen. Im Folgenden wird das Beispiel aus dem vorangegangen Kapitel abgeändert, sodass das Programm nur noch Module enthält, welche sich selbstständig in die Anwendung einfügen. Ein Modul wird den Programmablauf steuern. Dieses Modul wird hier RunningModule genannt. Es wird sich um die Ausgabe einer Nachricht kümmern, dabei verwendet es den OutputService aus dem vorangegangenen Beispiel. Dazu ist ein TextService gekommen, der die Nachricht bereitstellt.

    clip_image002
    Projektmappe einer modularisierten Anwendung


    Aufbau der Beispielanwendung

    Es ist geschafft! Das ausführende Programm stellt lediglich einen Container bereit, in dem mehrere Module referenziert werden können. Ein ModuleManager führt die Module aus. Dabei wird die Methode Initialize() ausgeführt, die jedes Modul durch das Interface IModule implementieren muss.

    Die Module OutputService und TextService registrieren in der ihre Funktionalitäten im UnityContainer der Program.cs. Dies ist möglich, weil er als Parameter im Konstruktor der jeweiligen Module übergeben wird.

    [sourcecode language=”csharp”]
    namespace TextService
    {

    public class TextModule : IModule
    {
    private IUnityContainer _container;

    public TextModule(IUnityContainer container)
    {
    _container = container;
    }

    public void Initialize()
    {
    _container.RegisterType();
    }
    }
    }
    [/sourcecode]

    Selbst ist das Modul. Registrierung der Inplementierung für den TextService.

    Wie in Bild 9 zu sehen wird das TextModule von dem ModuleManager gerufen. Der ModuleCatalog wendet seinerseits Dependency Injection an, und übergibt bei der Initialisierung des Moduls den UnityContainer der Anwendung an den Konstruktor. So bekommt die Anwendung Kenntnis von dem neuen TextService.

    Das gleiche Bild ergibt sich für das OutputModule. Nachdem die Services registriert sind, muss die Programmlogik gestartet werden, die ebenfalls aus der Program.cs entfernt und in einem Modul verlagert wurde.

    Diese Aufgabe übernimmt der RunningsService. Er liest die vorhandenen Ausgabedienste aus dem UnityContainer und gibt den Rückgabewert des Textservices sowohl auf die Konsole, als auch in einem Fenster aus.

    Hinweis: Der RunningService hat eine Abhängigkeit zu den Modulen OutputService und TextService. Da das RunningModule auf die Logik dieser Services zugreift, muss es als letztes initialisiert werden, damit der Unity Container die Services bereits kennt.

    [sourcecode language=”csharp”]
    public class Program
    {
    static void Main(string[] args)
    {
    UnityContainer container = new UnityContainer();

    container.RegisterInstance(
    new UnityServiceLocatorAdapter(container));

    TextLogger logger = new TextLogger();
    container.RegisterInstance(logger);

    ConfigurationModuleCatalog catalog = new ConfigurationModuleCatalog();

    catalog.AddModule(typeof (TextModule));
    catalog.AddModule(typeof (OutputModule));
    catalog.AddModule(typeof (RunningModule));

    container.RegisterInstance(catalog);

    container.RegisterType();
    container.RegisterType();

    IModuleManager manager = container.Resolve();
    manager.Run();
    }
    }
    [/sourcecode]

    Das Herzstück. – Komposition der Module in der Program.cs.

    Bevor der Modul Katalog in den Zeilen 13 bis 16 bestückt wird, werden in dem Unity Container vorher zwei noch unbekannte Objekte instanziiert.

    Der IServiceLocator bietet eine Abstraktion für den Unity Container. Wie bereits erwähnt gibt es mehrere Implementierungen der Dependency Injection. Weitere Container für .NET sind beispielsweise Autofac, Spring oder Ninject. Damit ein Projekt unabhängig von diesen DI- Containern ist, wird der Servicelcator eingesetzt. Er legt sich als Ebene über die Container und bietet eine zentrale Zugriffsmöglichkeit. Damit wird es möglich, dass mehrere DI- Container in einem Softwareprojekt eingesetzt werden können.

    clip_image002

    Die Abstraktion der DI- Container mittels Service Locator.

    In Zeile neun wird ein TextLogger- Objekt erzeugt, in dem zur Laufzeit des Programms Statusinformationen zu Ablaufprozeduren gespeichert und später ausgewertet werden können. Hier kann die Methode RegisterInstance<[Interface]>([Instance]) beobachtet werden, die nicht nur Typen einer Klasse registriert, sondern schon eine Instanz, die von der gesamten Anwendung verwendet werden kann.

    Kurz zum IModuleInitializer: Dieses Interface (zu sehen in Zeile 20) verlangt die Initialize- Methode. Diese finden wir wiederum in dem Interface IModule wieder, welches jedes unserer Module implementieren muss.

    Der ModuleManager hat eine Abhängigkeit zu dem Modulkatalog und initialisiert all dessen Module mit der Methode Run() in Zeile 24.

    clip_image004

    Initialisierung der Module einer Prismanwendung.

    Kurz: Es werden von allen Modulen die Initialize- Methoden gerufen. Sie können genutzt werden, um weitere Services im Unity Container zu registrieren, oder den Programmablauf zu steuern. Die Modularisierung ist damit vorerst abgeschlossen.

    Im Folgenden wird besprochen, wie einzelne Module untereinander kommunizieren können.

    Download der Anwendung zu diesem Beitrag:

    T_UnityApplication.zip

    Das Handwerk Teil 1 – Dependecy Injection

    [edit] Den Download zu diesem Beispiel findet ihr im nächsten Beitrag.

    In vorangegangen Posts wurde Prism kurz erklärt. Nun müssen wir in Erfahrung bringen, wie die Bestandteile von Prism funktionieren.

    Wie funktionier eine UI- Composition?

    Um dies zu realisieren wir das Pattern Dependency Injection eingesetzt. Aufgrund von klaren Definitionen der Schnittstellen werden die einzelnen Module in einer Oberfläche miteinander vereint. Zunächst wird das Grundkonzept der Dependency Injection erläutert, da dieses Pattern für Composite Applications in .NET ein essentieller Bestandteil ist.

    Mit Hilfe von Dependency Injection soll eine Anwendung flexibler gestaltet werden. Für die Umsetzung werden im Grunde vier Bestandteile benötigt:

  • Container
  • Eine Schnittstelle (Interface)
  • Beliebig viele Implementierungen der Schnittstelle (Klasse)
  • Ein Konsument für den Container
  • clip_image002[11]

    Schema für Dependency Injection (bitte anklicken zum vergrößern)

    Die gezeigte Darstellung zeigt, wie eine Entkoppelung der implementierten Logik von einer Anwendung erwirkt werden kann.

    Zu Beginn wird ein Interface definiert, zu dem dann beliebig viele Klassen programmiert werden können, die diese Schnittstelle implementieren. Dieses Vorgehen spiegelt bis jetzt die traditionelle Arbeitsweise wieder, die nun lediglich erweitert wird. Denn die programmierte Logik wird nicht direkt in der Anwendung instanziiert. Das heißt, dass zur Zeit des Kompiliervorgangs die Anwendung ihre Funktionen selbst nicht kennt. Sie besitzt jedoch ein Objekt in Form eines Containers. Der Container enthält eine List von Verträgen, denn er bestimmt zu welchem Interface, welche Klasse instanziiert wird. Der Container wird zur Laufzeit des Programms konfiguriert. Nur was ist der Gewinn dieser Vorgehensweise? Nun, es ist nun möglich während der Programmlaufzeit die Logik auszutauschen in Abhängigkeit benötigter Funktionen oder der Benutzerrechte liefert der Container eine Instanz der benötigten Objekte. Dabei muss nur beachtet werden, dass jegliche Instanz einer Klasse nur noch durch den Container erfolgen darf. Eine Implementierung dieses Containers bietet das Open Source Projekt Unity, dessen Funktionalität hier in einem Szenario demonstriert wird. Zunächst soll lediglich eine Nachricht auf der Konsole ausgegeben werden. Diese Implementierung ist sehr einfach:

    [sourcecode language=”csharp”]
    using System;

    namespace T_UnityApplication
    {
    class Program
    {
    private static string _messageText = "Alles in bester Ordnung!";

    static void Main(string[] args)
    {
    Console.WriteLine(_messageText);
    }
    }
    }
    [/sourcecode]

    In einem weiteren Schritt soll es ermöglicht werden, die Textnachricht auch in einem sich öffnenden Fenster anzuzeigen.

    Sicherlich ist es möglich diese Funktionalität dem Programm in der Program- Klasse hinzuzufügen. Jedoch soll die Anwendung für zukünftige Erweiterungen gut wartbar sein. Darum ist es überlegenswert die Ausgabe der Nachricht in einen externen Dienst auszulagern. Dazu möchten wir nun die Dependency Injection verwenden. Sie soll die unterschiedlichen Funktionalitäten und deren Beschreibungen, in der Form von Interfaces, verwalten

    Also wird der neue Service wird in einem Interface deklariert. In diesem Szenario muss eine Funktion implementiert werden, die nur eine Textvariable ausgeben kann. Die Definition könnte wie folgt aussehen:

    [sourcecode language=”csharp”]
    public interface IOutputService
    {
    void WriteMessage(string message);
    }
    [/sourcecode]

    Definition eines Interfaces.- Vorbereitung für Dependency Injection.

    Zu dem Interface können nun konkrete Implementierungen geschrieben werden, die eine Nachricht auf unterschiedliche Weise ausgeben können. Für den jetzigen Zeitpunkt soll ein Ausgabedienst für die Konsole und Einer für ein Ausgabefenster geschrieben werden.

    [sourcecode language=”csharp”]
    public class ConsoleOutputService : IOutputService
    {
    public void WriteMessage(string message)
    {
    Console.WriteLine(message);
    }
    }

    [/sourcecode]

    Ausgabe auf der Textvariable auf Konsole

    [sourcecode language=”csharp”]
    public class WindowOutputService : IOutputService
    {
    public void WriteMessage(string message)
    {
    MessageBox.Show(message);
    }
    }
    [/sourcecode]

    Ausgabe auf der Textvariable im Ausgabefenster.

    Beide Klassen implementieren das IOutputService Interface. Beide Klassen besitzen die Methode WriteMessage mit unterschiedlichen Ausgabemechanismen.

    Jetzt kommt der Unity Container ins Spiel. Er registriert diese Implementierungen in dem ausführbaren Programm. Die Registrierung kann beispielsweise in einer Liste von Diensten gespeichert werden und später dann ausgeführt werden.

    [sourcecode language=”csharp”]
    class Program
    {
    private static string _messageText =
    "Alles in bester Ordnung.";
    private static IEnumerable<IOutputService>
    _outputServices;

    static void Main(string[] args)
    {
    UnityContainer container = new UnityContainer();

    //Konfigurieren des Containers
    container.RegisterType<IOutputService,
    ConsoleOutputService>("OutputServiceOne");
    container.RegisterType<IOutputService,
    WindowOutputService>("OutputServiceTwo");

    _outputServices = container.ResolveAll
    <IOutputService>();

    WriteMessageToAllOutputServices();
    Console.ReadLine();

    }

    private static void WriteMessageToAllOutputServices()
    {
    foreach (IOutputService outputService
    in _outputServices)
    {
    outputService.WriteMessage
    (_messageText);
    }
    }
    }
    [/sourcecode]

    In Zeile 5 von wird eine Liste angelegt die Elemente vom Typ des Interfaces IOutputService speichern kann. Im Programm selbst wird zu Anfang eine Instanz des UnityContainers angelegt. Direkt im Anschluss werden die Ausgabedienste im Container registriert. In Zeile 18 werden mit der Methode Resolve schließlich alle Registrierten Klassen zu dem Interface instanziiert und in der Liste abgespeichert. Die Liste wird in der Methode ausgelesen. Die sich darin befindlichen Dienste können gestartet und ausgeführt werden. Das hier gezeigte Beispiel ist selbstverständlich noch nicht ausgereizt. Im Folgenden sollte noch die Nachricht in einen separaten Service ausgelagert werden. Auch die Methode WriteMessageToAllOutputServices sollte in eine Klasse verschoben werden, die den Programmablauf steuert. Das lauffähige Programm soll lediglich den Container konfigurieren können, der die Funktionen in Anwendung einfügt.

    Der Gewinn, der durch den Einsatz von Dependency Injection entsteht, ist die Entkopplung des Programms von der beinhaltenden Logik.

    Herunterladen und Bereitstellung des Frameworks.

    Den Composite Applcation Guidance findet ihr auf Codeplex.

    Nach dem herunterladen der neusten Version von Prism muss lediglich das Projekt im Visual Studio kompiliert werden.
    Die unten aufgeführten DLLs müssen in jedem “CAL enabled Project” referenziert sein, um alle Funktionen nutzen zu können.

  • Microsoft.Practises.Composite.dll
  • Microsoft.Practises.Composite.Presentation.dll
  • Microsoft.Practises.Composite.UnityExtensions.dll
  • Microsoft.Practises.Composite.ServiceLocation.dll
  • Microsoft.Practises.Composite.Unity
  • Jetzt haben wir das Werkzeug nun müssen wir uns dem Handwerk widmen…

    Das Ziel von Composite UI (Prism)

    Um die Motivation für dieses Thema zu erhöhen seien noch einige Ziele genannt, die hinter Prism stehen. (Post über Architektur von Prism)

    Als aller Erstes ist die Wiederverwendbarkeit zur erwähnen. In Prism werden Module programmiert, die jeweils durch eine Assembly oder XAP- Datei repräsentiert werden. Die Module kapseln sowohl die Logik der zu verwendenden Daten, als auch die Oberflächenbeschreibung. Diese Module werden zur Laufzeit der Anwendung hinzugefügt. Sie müssen innerhalb einer WPF- oder Silverlightanwendung selbstständig funktionieren. Jedes Modul kann somit in unterschiedlichen Projekten zum Einsatz kommen.

    Die Funktionalität einer Anwendung wird in viele Module geteilt. Damit sinkt die zu implementierende Logik pro Modul. Wenn die Komplexität des Quellcodes kleiner wird, lässt sich das Modul viel besser mit Unit Tests abdecken. Auch die Tests werden somit einfacher.

    Jedes Modul wird für sich mit dem MVVM- Pattern realisiert, um eine klare Trennung zwischen User Interface und Geschäftslogik zu wahren.

    Die Module können getrennt und parallel entwickelt werden. In einem Entwickler Team kann ein Modul als Arbeitspaket an einer Gruppe des Teams zugeteilt werden.

    Dann lasst uns mal starten.

    Was ist Prism?

    Prism ist eine Zusammenstellung mehrerer Programmbibliotheken, die bei der Erstellung modularer Anwendungen unterstützend eingreifen kann. Dieses Framework kann sowohl in WPF, als auch Silverlightanwendungen angewendet werden. Die wichtigsten Bestandteile dieser Bibliothek werden hier erläutert.

    Es werden von einander entkoppelte Module erstellt, die in einer gemeinsamen Oberfläche zusammengeführt werden können. Die Module können ebenso schnell entfernt beziehungsweise ersetzt werden.

    clip_image002

    Architekturschema einer Anwendung in Prism, in vereinfachter Form.

     

    Wie in der Darstellung zu sehen, gibt es mehrere Module, die in einem Katalog gelistet werden können. Der Katalog kann durch ein Programm gerufen werden und in definierte Regionen auf der Oberfläche platziert werden.

    Dies führt zu einer hohen Flexibilität der Anwendung. Die Anwendung von Prism bietet sich vor allem bei Projekten an, die eine lange Laufzeiten haben und sich Anforderungen schnell ändern können.

    In Internet tritt Prism auch noch unter dem alten Namen Composite WPF oder Composite UI auf.

    Auf der Projektseite von Prism gibt es sehr viel Material, welches die Anwendung des Framesworks zeigt.

  • Getting Started with Prism
  • Videos und Blogs
  • Die Prism Knowledge Base

    Einige Themen werden exklusiv auf diesem Blog besprochen. 😉

     

  • Das Command Pattern–Die View erteilt hier keine Befehle ;)

    Nach der Bereitstellung von INotifyPropertyChanged im vorangegangen Post, können wir jetzt damit beginnen dem Nutzer eine einfache Interaktion bereitzustellen.
    Das Command Pattern erlaubt hier das Ausführen von Operationen, von denen die View keine Kenntnis hat. Das bedeutet auch hier wieder: Keine logik in der View. 😉 Die Oberflächenelemente können an Commands gebunden werden. Sobald das Command durch ein Event auf der Oberfläche angestoßen wird, führt es eine Aktion aus.

    Das Command ist ein Objekt, das über Parameter konfiguriert werden kann. Die Instanzierung des Commands erfolgt im View Model und enthält die zu verarbeitende Logik.

    Dieses Vorgehen verstößt allerdings gegen die getätigte Überlegung der Architektur. Keine Logik in der View! Dieses Problem kann leicht mit dem Command Pattern behoben werden.

    Das Command Pattern erlaubt das Ausführen von Operationen, von denen die View keine Kenntnis hat. Die Oberflächenelemente können an Commands gebunden werden. Sobald das Command durch ein Event auf der Oberfläche angestoßen wird, führt es eine Aktion aus.

    Das Command ist ein Objekt, das über Parameter konfiguriert werden kann. Die Instanzierung des Commands erfolgt im View Model und enthält die zu verarbeitende Logik.

    clip_image002[5]

    Schemata für gebundenes Command im MVVM

    Das Command kann im XAML der View mittels Data Binding instanziert werden. Im View Model muss für das Command eine Methode angegeben werden, die beim Aufruf des Commands abgearbeitet wird (Execute). Um zu überprüfen, ob das Command ausgeführt werden darf, kann zusätzlich eine Methode referenziert werden (CanExecute). Somit können Eingabedaten validiert werden.

    Für die Implementierung von Commands stellt das .NET- Framework im Namensraum System.Windows.Input das ICommand- Interface zur Verfügung. Diese Implementierung wird in dieser Arbeit nicht verwendet, da sie nur WPF- Anwendungen unterstützt. Für den Fall, dass eine Clientanwendung zentralisiert zur Verfügung gestellt werden soll, wäre es für die Migration nicht dienlich. Das Microsoft Pattern and Practises Team stellt hier eine eigene Implementierung zur Verfügung die sowohl für WPF, Windows Forms und auch Silverlight genutzt werden kann.

    Im folgenden Listing wird zu dem bestehenden Beispiel ein Button hinzugefügt, der an ein Command gebunden ist. Bei einem Klick auf den Button wird das Command ausgeführt, welches die Statusnachricht aus dem Model laden soll.

    Beginnen wir mit der Definition des Commands im View Model.

    [sourcecode language=”csharp”]
    using System.ComponentModel;
    using Microsoft.Practices.Composite.Presentation.Commands;

    namespace T_SimpleDataBinding
    {
    public class StatusMessageViewModel : INotifyPropertyChanged
    {
    // private Members
    private string _statusMessage;

    // public Properties
    string StatusMessage
    {
    get { return _statusMessage; }
    set
    {
    _statusMessage = value;
    OnPropertyChanged("StatusMessage");
    }
    }

    // Commands
    private DelegateCommand<object>
    _getStatusMessageCommand;

    public DelegateCommand<object>
    GetStatusMessageCommand
    {
    get
    {
    if (_getStatusMessageCommand == null)
    {
    return _getStatusMessageCommand =
    new DelegateCommand<object>(
    o =>
    {
    StatusMessageModel model =
    new StatusMessageModel();

    model.StatusRequestCompleted +=
    ModelStatusRequestCompleted;

    model.BeginStatusRequest();
    },
    c =>
    {
    return true;
    });
    }
    return _getStatusMessageCommand;
    }
    }

    public void ModelStatusRequestCompleted
    (object sender, StatusEventArgs e)
    {
    StatusMessage = e.Result;
    }

    #region Implementation of INotifyPropertyChanged
    .
    .
    .
    #endregion
    }
    }
    [/sourcecode]
    Listing Bereitstellung eines Commands im View Model.

    Der Quellcode für den Command sieht zunächst kompliziert aus. Nachdem die using- Direktive in Zeile 02 hinzugefügt wurde, kann das Objekt DelegateCommand verwendet werden. Es kann zwei Parameter entgegen nehmen,- die auszuführende Methode, die durch eine Aktion auf der Oberfläche ausgeführt werden soll und die Methode zu Validierungszwecken. Das Command wird genau wie zum früheren Zeitpunkt die StatusMessage als Eigenschaft mit einem get definiert, damit das Data Binding mit der View funktioniert (ab Zeile 21). Wenn das DelegateCommand noch nicht definiert ist, wird dies bei der ersten Abfrage getan. Es wird eine Instanz des DelegateCommands erzeugt. Mit Hilfe von Lambda Ausdrücken, ab Zeile 30 und 40, werden die auszuführenden Funktionen dem DelegateCommand übergeben. Lambdas können als Kurzschreibweisen für Delegates genutzt werden.

    Nachdem die Definition des Commands abgeschlossen ist kann die erstellte Eigenschaft an die View gebunden werden. In diesem Beispiel wird ein Button mit dem Command gesetzt.

    [sourcecode language=”html”]
    <UserControl x:Class="T_SimpleDataBinding.StatusMessageView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:Lokal="clr-namespace:T_SimpleDataBinding"
    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation">
    <UserControl.Resources>
    <Lokal:StatusMessageViewModel x:Key="BindingViewModel"/>
    </UserControl.Resources>
    <UserControl.DataContext>
    <Binding Source="{StaticResource BindingViewModel}"/>
    </UserControl.DataContext>
    <Grid>
    <Grid.RowDefinitions>
    <RowDefinition Height="192*" />
    <RowDefinition Height="108*" />
    </Grid.RowDefinitions>
    <TextBlock
    VerticalAlignment="Center"
    HorizontalAlignment="Center"
    Text="{Binding Path=StatusMessage}" />
    <Button
    cal:Click.Command="{Binding GetStatusMessageCommand}"
    Content="get Status"
    VerticalAlignment="Center"
    HorizontalAlignment="Center"
    Grid.Row="1" />
    </Grid>
    </UserControl>
    [/sourcecode]
    Listing UI + Button mit gebunden Command.

    Dieser Button wurde in das Grid des vorangegangenen Beispiels hinzugefügt. Besonders ist hier das Attribut Click.Command im cal Namensraum. Diese Erweiterung wird ebenfalls durch die Bibliothek des Microsoft Pattern and Practises Teams zur Verfügung gestellt. Spätestens hier sollte jedem klar sein wie ungeheuer mächtig Data Binding sein kann. Damit wurde die erste Interaktion mit der UI ermöglicht.

    Hinweis: Durch die Implementierung es Observer Patterns in Form von INotifyPropertyChanged wird auf der View das Ergebnis des ausgeführten DelegateCommands automatisch dargestellt.