8. März 2008 – 20:35 von Andreas
Die Enterprise Library ist eine feine Sache! Das offene Provider-Konzept ermöglicht es immer wieder neue Application Blocks lose gekoppelt und trotzdem gut intergriert zu implementieren. Ein schönes Beispiel für diese Integration bietet der (relativ
neue Policy Injection Application Block der Microsoft patterns & practices group. In diesem kleinen Beitrag möchte ich euch zeigen wie einfach man in seinem Code Excpetion-Handling einbringen kann ohne den eigentlichen “Business”-Code damit zu belasten (AOP lässt grüßen).
Nun aber zu einem praktischen Beispiel:
Zunächste laden wir die aktuelle Enterprise Library unter: Enterprise Library 3.1 - May 2007 herunter und installieren diese.
Dann legen wir ein neues Windows Forms-Projekt in VisualStudio an. Als nächstes benötigen wir eine App.config, in welcher die Konfiguration für die Enterprise Library, für unsere Applikation hineinkommt. In unser leeres WindowsForms-Projekt fügen wir nun eine Klasse für unsere “Business-Logik” ein. (Normal sollte dies natürlich in einem extra Projekt gemacht werden! Zu Demozwecken verzichten wir aber darauf.) Als nächstes ziehen wir einen Button auf das Formular und erstellen ein Click-Ereignis für diesen Button. Darin wird dann unser Business-Logik-Code aufgerufen.
In diesem Beispiel wollen wir mit Hilfe der Enterprise Library bei einer Exception, Informationen über den Fehler in einer MessageBox ausgeben. Um auf die entsprechenden Klassen der Enterprise Library zugreifen zu können benötigen wir noch die richtigen Assembly-Referenzen und Namespaces. Folgende DLLs müssen also für unser Beispiel eingebunden werden (diese befinden sich unter [”Installationsverzeichnis”\Microsoft Enterprise Library 3.1 - May 2007\Bin]):

Der komplette Code für die “Business”-Klasse und das Formular mit unserem Click-Ereignis sollte folgendermaßen aussehen:
-
using System;
-
using System.Collections.Generic;
-
using System.ComponentModel;
-
using System.Data;
-
using System.Drawing;
-
using System.Linq;
-
using System.Text;
-
using System.Windows.Forms;
-
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;
-
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers;
-
using WinFormsMessageBoxExceptionHandler;
-
-
namespace WindowsFormsPolicyInjectionTest
-
{
-
public partial class Form1 : Form
-
{
-
public Form1()
-
{
-
InitializeComponent();
-
}
-
-
private void button1_Click(object sender, EventArgs e)
-
{
-
// BusinessLogicClass-Instanz ueber die PolicyInjection-
-
// Klasse erzeugen lassen, so dass die konfigurierten Policies
-
// als Aspekte (siehe Aspektorientierte Programmierung) die
-
// auf BusinessLogicClass-Instanz zugreifen koennen.
-
BusinessLogicClass bl = PolicyInjection.Create<BusinessLogicClass>();
-
bl.Foo();
-
}
-
}
-
-
class BusinessLogicClass : MarshalByRefObject
-
{
-
public void Foo()
-
{
-
MessageBox.Show("Hello");
-
throw new Exception
("bad exception ;)");
-
}
-
}
-
}
Schauen wir uns zuerst die “BusinessLogicClass”-Klasse an. Sofort fällt auf, dass sie von MarshalByRefObject erbt. Dies müssen wir machen, um die Methoden der Klasse (in userem Fall die Methode Foo()) vom Policy Injection Block “abfangbar” zu machen. In der Konfiguration des Policy Injection Blocks kann ich nämlich per Regel festlegen, welche Methoden/Klassen die Handler der Policy verarbeiten sollen. Bearbeiten wir also nun unsere App.config mit Hilfe des Tools EntLibConfig.exe (zu finden unter [”Installationsverzeichnis”\Microsoft Enterprise Library 3.1 - May 2007\Bin]). Nachdem die App.config in EntLibConfig.exe geöffnet fügen wir den Policy Injection Application Block hinzu:

Als nächstes müssen wir dem Block eine Policy hinzufügen:

Nun müssen wir der neu erstellten Policy sagen, wann diese eingreifen soll. Da wir wollen, dass Sie bei allen Methoden unserer “Business”-Klasse reagieren soll, wählen wir als “Matching Rule” die “Type Matching Rule”:

Nun müssen wir noch die genaue Klasse festlegen, auf welche die “Type Matching Rule” reagieren soll (Die Reihenfolge der Aktionen ist auf dem Bild nummeriert):


Nun haben wir also festgelegt auf welche Klasse die Policy schauen soll. Jetzt benötigen wir noch einen geeigneten Handler. Da der Handler eine Excpetion abfangen soll wählen wir den vordefinierten “Exception Handling Handler”:

Bisher haben wir uns nur um den Policy Application Block gekümmert und hierfür entsprechende Konfigurationen durchgeführt. Wir benötigen aber noch den Exception Handling Block, der die eigentliche Excpetion behandeln und mit dem “Exception Handling Handler” der soeben erstellten Policy verbunden werden soll. Hierzu fügen wir zuerst den Exception Handling Application Block hinzu:

Diesem Block fügen wir dann eine “Exception Policy” hinzu:

Dieser Policy müssen wir sagen, auf welchen Exception-Type sie reagieren soll (in unserem Fall eine normale Excpetion):


Da wir wollen, dass Informationen über die geworfene Excpetion in einer MessageBox ausgegeben werden sollen und die Exception danach nicht mehr weitergeworfen werden soll müssen wir dieses Verhalten auch konfigurieren:


Da es keinen vordefinierten Handler gibt, welcher Informationen über eine Exception in einer MessageBox ausgibt müssen wir einen eigenen “Custom Handler” implementieren. Zuerst legen wir den Custom Handler aber in unserer Konfiguration an:

Kommen wir nun also zum Implementieren des Custom Handlers. Hierzu erstellen wir ein neues Klassenblibliotheks-Projekt in VisualStudio. Das Projekt benötigt folgende Referenzen:

Wir nennen unseren Custom Handler “WinFormsMessageBoxExceptionHandler”. Die Implementierung enthält folgenden Code:
-
using System;
-
using System.Collections.Generic;
-
using System.Text;
-
using System.Windows.Forms;
-
using Microsoft.Practices.EnterpriseLibrary.Common;
-
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
-
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
-
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration;
-
using System.Collections.Specialized;
-
-
namespace WinFormsMessageBoxExceptionHandler
-
{
-
[ConfigurationElementType
(typeof(CustomHandlerData
))]
-
public class MessageBoxExceptionHandler : IExceptionHandler
-
{
-
-
public MessageBoxExceptionHandler(NameValueCollection collection)
-
{
-
}
-
-
#region IExceptionHandler Members
-
-
public Exception HandleException(Exception exception, Guid handlingInstanceId)
-
{
-
MessageBox.Show("Following error occurs: " + exception.Message
-
,"Error"
-
, MessageBoxButtons.OK
-
, MessageBoxIcon.Error);
-
return exception;
-
}
-
-
#endregion
-
}
-
}
Unsere Custom Handler-Klasse “MessageBoxExceptionHandler” muss das Interface “IExceptionHandler” und dort die Methode “HandleException” implementiern. “HandleException” bekommt die geworfene Exception als Parameter übergen und gibt dann wieder eine Exception zurück. Wir geben die Informationen der ursprünglich geworfenen Excpetion per MessageBox aus und die Excpetion selber einfach ohne Veränderung wieder zurück. Außerdem benötigt die Klasse “”MessageBoxExceptionHandler” einen Konstruktor mit einem “NameValueCollection”-Parameter haben. Zusätzlich hierzu muss der Klasse noch folgendes Klassen-Attribut hinzugefügt werden: [ConfigurationElementType(typeof(CustomHandlerData))]
Zuletzt MUSS die Assembly noch mit einem “strong name key file” signiert werden (ansonsten erhält man folgende Fehlermeldung beim Versuch des Ladens der Assembly: “There were no types found in the assembly “AssemblyName” that implement or inherit from the base type “Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.IExceptionHandler”):

So, das wäre geschafft! Jetzt müssen wir das Projekt noch builden und können dann unseren Custom Handler in die Konfiguration einbauen. Dies tun wir, indem wir die “Type”-Eigenschaft des Custom Handlers entsprechend auf unseren selbst erstellten “WinFormsMessageBoxExceptionHandler” setzen:


Als letztes müssen wir nun noch unseren “Exception Handling Handler” aus dem Policy Injection Application Block mit der “Exception Policy” aus dem Exception Handling Application Block verknüpfen. Dies machen wir hier:


Es scheint geschafft zu sein. Wir können die Konfiguration speichern und unsere Arbeit testen. Aber halt!! Unsere “WinFormsMessageBoxExceptionHandler”-Assemby muss auch noch in unserem Implementierungsprojekt referenziert werden:

Jetzt können wir unsere Test-WinForms-Anwendung aber endlich starten und testen. Und siehe da, nachdem der Button geklickt wurde und die Zeile “throw new Exception(”bad exception ;)”);” abgearbeitet wurde bekommen wir unsere MessageBox:

Wie man sieht konnten wir das Exception-Handling schön von dem eigentlichen Implementierungs-Code auslagern und zudem noch konfigurabel machen. Weitere sinnvolle Szenarien, wie Logging, usw. lassen sich natürlich auf die gleiche Weise wunderbar abbilden.
Da kann ich nur viel Spaß mit dem Policy Injection Application Block wünschen ;).
Posted in .NET Entwicklung, Enterprise Library, Interessante Links, SW Architecture | No Comments »