SP.UI.ModalDialog.showModalDialog() do not work under SharePoint 2013

By migration our Solutions2Share License Management Solution from SharePoint 2010 to SharePoint 2013 the SharePoint Modal Dialog didn’t opened.

SharePoint 2010 Example:

   1: function ShowServerInformation() {

   2:         var options = {

   3:             url: '/_admin/Solutions2Share/LicenseManagement/GeneralServerInformation.aspx',

   4:             tite: 'Server Information',

   5:             allowMaximize: false,

   6:             showClose: true,

   7:             width: 430,

   8:             height: 230

   9:         };

  10:

  11:         SP.UI.ModalDialog.showModalDialog(options);

  12:         return false;

  13:     }

It’s very easy to fix this problem.

  1. Remove the Java Script reference.
    <script src=”/_layouts/sp.js” type=”text/javascript”></script>
    <script src=”/_layouts/SP.UI.Dialog.js” type=”text/javascript”></script>
  2. Add to the url variable “?IsDlg=1″`
  3. Replace the command SP.UI.ModalDialog.showModalDialog() with the new command SP.SOD.execute(‘sp.ui.dialog.js’, ‘SP.UI.ModalDialog.showModalDialog’, options);

After this few changes your solution will work correctly.

SharePoint 2013 Example:

   1: function ShowServerInformation(featureId) {

   2:       var options = {

   3:           url: '/_admin/Solutions2Share/LicenseManagement/ServerInformation.aspx?featureId=' + featureId + "&IsDlg=1",

   4:           title: 'Server Information',

   5:           allowMaximize: false,

   6:           showClose: true,

   7:           width: 430,

   8:           height: 230

   9:       };

  10:

  11:       SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', options);

  12:

  13:       return false;

  14:   }

Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Unter aspektorientierter Programmierung versteht man die Beeinflussung des Quellcodes von einer dritten Komponente, wie z.B. das Modifizieren von Klassen und Funktionen während des Kompilierens des Quellcodes.

clip_image002

In der oberen Darstellungen sehen wir eine beliebige Methode; zusätzlich zu der Methode wurde ein Aspekt vom Typ MethodBound definiert. Der Aspekt soll beim Start der Methode eine spezifische Aktion ausführen, sowie im Fehlerfall also auch beim erfolgreichen Verlassen der Funktion.
Um aspektorientiert programmieren zu können wird eine dritte Komponente benötigt, von der die entsprechenden Ereignisse zur Verfügung gestellt werden und die in den bereits vorhandenen Quellcode eingreifen kann. In diesem Beispiel und Innerhalb der Solutions2Share.Common wird PostSharp verwendet. Beim Kompilieren des Quellcodes reagiert PostSharp und erkennt dass der Methode der Aspekt zugewiesen wurde und baut daraus eine neue Funktion, wie sie im nächsten Abbild aufgezeigt wird:

clip_image002[6]

In diesem Fall sehen wir, dass unsere bereits vorhanden Methode um den entsprechenden Aspekt erweitert worden ist. Der Programmierer fügt der Methode den Aspekt in Form eines Attributes hinzu. Der Aspekt muss nicht jeder Methode separat zugewiesen werden, er kann auch auf die komplette Klasse oder Assembly verordnet werden. Wie bereits im Artikel „ExceptionHandling und Logging“ beschrieben, stellt die Solutions2Share.Common bereits dabei einige Klasse zur Verfügung, mit der die Fehlerbehandlung und das Auffinden von Fehlern vereinfacht werden soll. Um diese verwenden zu können ist noch immer ein Try-Catch in jeder Methode notwendig. Von der Methode selbst ist nur der Name erhalten, um weitere Informationen zu erhalten, müssten diese in jeder Methode einzeln eingebaut werden. Auch ohne die weiteren Informationen manuell einzubauen, kann von den Entwicklern leicht „vergessen“ werden ein Try-Catch in die Funktion einzufügen. Aus diesem Grund bietet die Solutons2Share.Common bereits einen Aspekt an, der das Logging für die Methoden der Applikation übernimmt. Im Fehlerfall wird automatisch die ExceptionHandling-Klasse, wie bereits im vorherigen Artikel beschrieben, aufgerufen und durchgereicht, wodurch sich der Entwickler bereits das Try-Catch sparen kann, bzw. es immer automatisch implementiert ist. Dadurch werden jedoch nur der Name der Methode und die Fehlermeldung an sich protokolliert. Zur schnellen Auffindung des Fehlers sind häufig mehr Informationen gewünscht oder auch benötigt, die so nicht erhältlich sind oder nur mit Aufwand separat eingebaut werden können.
Durch den Methoden-Aspekt kann nicht nur auf einen Fehlerfall reagiert, sondern auch auf den Ablauf der Methode selbst zugegriffen werden.
Dadurch haben wir die Möglichkeit sämtliche Parameter der Methode oder Funktion mit ihren jeweiligen Werten auszulesen und zu protokollieren, wodurch der Programmierer direkt erfahren kann, mit welchen Parametern die Methode aufgerufen wurde und diese evtl. nachstellen.
Dies ist nur ein Beispiel für Aspektorientierte Programmierung, aber hier bietet die Solutions2Share.Common bereits eine Hilfs-Klasse über die neben dem Fehlerfall auch der Aufruf und die Laufzeit der Methode festgehalten werden können.

Part VII: Smart Little Helpers


Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Wie bereits gezeigt wurde, verfügt die Solutions2Share.Common über einige große Komponenten, die das Leben des Entwicklers erleichtern können. Neben den großen Komponenten verfügt Solutions2Share.Common über eine große Anzahl von kleineren Komponenten, die auch im täglichen Leben sehr hilfreich sein können. Diese kleineren Komponenten befinden sich zum einen in den bereits verfügbaren Data-Modulen, wenn sie vom Context der Anwendung abhängig sind. Dazu zählt eine erweiterte Funktion zum Verschicken von E-Mails, hier werden die SMTP-Einstellungen aus SharePoint ausgelesen, die Standard-E-Mail-Funktion von SharePoint jedoch erweitert. Es können z.B. ein fester Absender definiert oder E-Mails mit Anhängen versandt werden. Der größte Teil der kleinen Helfer-Funktionen sind als Extension-Methods in der Solutions2Share.Common hinterlegt, da diese nicht vom aktuellen SharePoint-Context abhängig sind. Viele dieser Extension-Methods sind nicht deshalb nützlich, weil sie eine komplexe oder aufwändige Aufgabe erfüllen, sie erleichtern dem Entwickler einfach das tägliche Leben, indem sie häufig verwendete Aufrufe schnell und einfach in einer Funktion wiederspiegeln und über IntelliSense aufgerufen werden können. Dies erhöht schlicht den Komfort bei der Entwicklung, die Lesbarkeit des Quellcodes und erspart dem Entwickler das Schreiben von relativ umständlichen Konstrukten.

Vergleichsoperatoren

Während der Programmierung begegnen einem immer dieselben Vergleichs-Operationen, z.B. innerhalb von If-Abfragen, Schleifen usw.
Im Folgenden ist eine Auflistung von Vergleichs-Operatoren im Vergleich zum Methoden-Aufruf über Extension-Methods und zur standardschreibweise in C# dargestellt.
Der Unterschied wird vor allem sichtbar, wenn viele Operatoren miteinander verkettet sind.

Bild 10

Caml-Operationen

Caml ist eine Abfrage-Sprache, die in SharePoint zur Filterung von Listen-Einträgen verwendet wird. Da Caml auf XML basiert, ist sowohl das manuelle als auch das dynamische Zusammenstellen von Abfragen relativ umständlich.
Im Folgenden wird ein Beispiel einer Caml-Abfrage mit zwei Filtern dargestellt:

image

Um dies etwas zu erleichtern, enthält die Solutions2Share.Common ein paar Hilfsfunktionen, in denen die Verknüpfung der Filter übernommen wird. Die Funktionen erwarten die einzelnen Filter in Form einer String-Liste und fügen diese dann im XML-Format zusammen und geben die fertige Query zurück.
Im Folgenden ein Beispiel, wie die obige Query mithilfe der Extension-Methods zusammengebaut werden würde.

 image

Das Zusammenfügen der einzelnen Teile wird von der Method „GetFullAndJoinedCamlQuery“ übernommen, wodurch das Erstellen von dynamischen Caml-Queries deutlich vereinfacht wird.

SharePoint-Operationen

In der Solutions2Share.Commen sind noch viele weitere SharePointspezifische Extension-Methods vorhanden, die hier nicht einzeln aufgelistet werden.
Viele von diesen werden auch intern in der Solutions2Share.Common verwendet und sind z.B. für das Mapping zwischen den Listen-Einträgen und den Business-Klassen zuständig, aber auch für den allgemeinen Gebrauch nützliche Extension-Methods z.B. für das Setzen von Berechtigungen von Listen-Elementen.

Part VI: Dynamische Einstellungs-Seite

Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Wie bei jeder anderen normalen Anwendung wird auch in SharePoint-Projekten eine Möglichkeit benötigt, mit der vom Benutzer Einstellungen für die Anwendung getätigt und geändert werden können. Diese im Folgenden SettingsPage genannte Seite ist meistens über die Site-Einstellungen erreichbar. Die Settings-Page ist in den meisten Fällen eine SharePoint-Seite, in der die einzelnen Einstellungs-Möglichkeiten aufgelistet und bearbeitet werden können.
Die Einstellungen werden meistens über eine weitere Einstellungs-Klasse im PropertyBag des SharePoint-Webs gespeichert. Die Page an sich dient nur als Oberfläche für den Anwender um die Einstellungen aus der Einstellungs-Klasse darzustellen und abänderbar zu machen. Innerhalb der SettingsPage geschieht nochmal ein manuelles Mapping zwischen den Eigenschaften der Einstellungs-Klasse und den Steuerelementen der SettingsPage selbst. Für das Anlegen der SettingsPage muss neben der Platzierung mehrerer Steuerelemente innerhalb der ASPX-Seite auch das Mapping zwischen den Steuerelemente und der Einstellungs-Klasse manuell beim Auslesen und Speichern vorgenommen werden. Zusätzlich müssen die Texte in der Ressourcen-Datei angelegt und die Referenzen zu den Ressourcen-Dateien in den Eigenschaften der Steuerelemente hinterlegt werden. Dies ist umständlich und stellt eine wenig Anspruchsvolle und eintönige Aufgabe für den Entwickler dar. SettingsPages werden ab einer gewissen Größe sowohl für den Entwickler, als auch für den Endbenutzer recht unübersichtlich zu pflegen. Die Solutions2Share.Common stellt die DynamicSettingsPage zur Verfügung, die das Anlegen der SettingsPage für den Entwickler erleichtert und dem Benutzer eine übersichtlichere Einstellungs-Seite zur Verfügung stellen soll. Bei der DynamicSettingsPage gibt es keine direkte Trennung mehr zwischen der SettingsPage und der Einstellungs-Klasse, die Einstellungs-Klasse stellt hier die zentrale Komponente dar. Die DynamicSettingsPage stellt dynamisch den Inhalt der Einstellungs-Klasse dar. Das Anzeigen der Controls, sowie das Darstellen und Speichern der Werte der Einstellungen wird über die DynamicSettingsPage dynamisch gehandelt, wodurch kein manuelles Mapping mehr benötigt wird. Im Gegensatz zur ursprünglichen Einstellungs-Klasse, in der hauptsächlich Strings hinterlegt werden konnten, können jetzt komplexere Einstellungen hinter einer einzelnen Eigenschaft hinterlegt werden. Für die Art und Darstellung der Einstellung sind vordefinierte Einstellungs-Typen zuständig. Bei Bedarf können beliebig viele Einstellungs-Typen selbst definiert werden. In der Einstellungs-Klasse wird lediglich der Type der Einstellung definiert, die Darstellung wird vom WebControl des Types übernommen. Die DynamicSettingsPage kann so dynamisch das Control des jeweiligen Types darstellen. Für einfache Einstellungen wurden bereits Typen wie TextSettingsEntry, CheckBoxSettingsEntry oder RichTextSettingsEntry vordefiniert. Aber auch komplexere Typen wie ServerLoginSettingsEntry, in denen der Name des Servers, der Loginname und das Passwort hinterlegt werden können, sind bereits vordefiniert. Auf diese Werte kann über eine Eigenschaft der Klasse zugegriffen werden. Zusätzlich zu den Einstellungs-Typen wurde noch jeweils ein Settings-Control definiert, das zu dem jeweiligen Typ innerhalb der Einstellungs-Seite dargestellt wird. Zum Typ MailSettingsEntry, welches den Betreff und den Inhalt einer E-Mail enthält wird das Control MailSettingsControl dargestellt, wie im folgenden Bild verdeutlicht wird: clip_image002 In der DynamicSettingsPage sind keine Anpassungen für die Darstellung der Einstellung notwendig, es werden lediglich die Eigenschaften aus der Einstellungs-Klasse ausgelesen und dargestellt. In der Einstellungs-Klasse ist nur der Name der Einstellung und dessen Typ definiert: clip_image004 Im Standard werden in der DynamicSettingsPage alle Einstellungen untereinander aufgelistet dargestellt: clip_image006 Bei sehr vielen Einstellungen innerhalb einer Eintellungs-Seite kann dies leicht unübersichtlich werden. Für diesen Fall können die Einstellungen über eine DropDown-Liste ausgewählt werden. Hier wird nur die aktuell ausgewählte Eigenschaft dargestellt: clip_image008 Für den Entwickler entsteht kein weiterer Aufwand innerhalb der Einstellungs-Seite, wenn eine Einstellung hinzugefügt bzw. entfernt wird. Einstellungen müssen lediglich in die Einstellungs-Klasse eingefügt bzw. gelöscht werden. Die Texte der Einstellungen werden aus Ressourcen-Dateien ausgelesen, die benötigten Ressourcen-Einträge werden über das Einstellungs-Control definiert. Über den Url-Parameter „ShowAllEmptyResources“ können alle nicht gefüllten von den Einstellungs-Controls verwendeten Ressourcen-Einträge aufgelistet werden:

clip_image009
Das Anlegen und Füllen der Ressourcen-Einträge ist der einzige Schritt, der noch vom Entwickler durchgeführt werden muss. Über die DynamicSettingsPage in der Solutions2Share.Common können schnell Einstellungs-Seiten erstellt und bearbeitet werden. Durch die Einstellungs-Typen wird eine standardisierte Darstellung der Einstellungen und Namensgebung der Ressourcen-Einträge gewährleistet.

Part V: SharePoint-Definitionen automatisiert erstellen

Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Wie bereits im Artikel „Mapping zwischen Business-Objekten und SharePoint-Listen“ verfügt die Solutions2Share.Common-Bibliothek über Komponenten zur Automatisierung des Mappings zwischen den Eigenschaften der Business-Klassen und den Spalten der SharePoint-Spalten. Das Mapping wird über die Attribute der Eigenschaften der jeweiligen Business-Klasse automatisiert. In diesem Artikel wurde beschrieben, wie die Einträge aus der SharePoint-Liste in Business-Objekte umgewandelt werden und wie die Werte aus den Objekten wieder in die SharePoint-Liste geschrieben werden. Um das Mapping realisieren zu können, müssen die Listen bereits innerhalb der SharePoint-Site angelegt worden sein. Innerhalb von SharePoint-Projekten wird der Aufbau der einzelnen Listen in der Regel über Definitions-Dateien festgelegt und diese Listen über SharePoint-Features innerhalb der SharePoint-Site angelegt. SharePoint-Features und –Definitions-Dateien sind XML-Dateien, die innerhalb des Projektes angelegt werden. Nach dem Deployment der Lösung und der Aktivierung des Features innerhalb der SharePoint-Site werden die Listen und Bibliotheken automatisch anhand der Definition-Dateien innerhalb der Site angelegt. Das Erzeugen der Definitions-Dateien ist eine wenig beliebte Aufgabe, das sie relativ anspruchslos, Zeitaufwendig und Fehleranfällig ist.
Über die Business-Klassen sind Aufbau und Struktur der benötigten Listen und Bibliotheken bereits bekannt. Es ist also möglich aufgrund der Struktur der Business-Klassen den Aufbau der Listen in SharePoint zu ermitteln. In der folgenden Abbildung ist ein Beispiel von mehreren Business-Klassen aufgezeigt, wie sie sich innerhalb eines Projektes befinden können:

image

Hierbei handelt es sich um unterschiedliche Klassen mit Eigenschaft von unterschiedlichen Typen. Es handelt sich hierbei Standard-Typen wie String, Integer oder DateTime-Eigenschaften, aber auch um selbst definierte Enums und Verbindungen zwischen den einzelnen Klassen. In der nächsten Abbildung ist beispielhaft der Aufbau einer der Business-Klassen dargestellt:

image 

Über die reine Klassen-Struktur erfahren wir bereits den Namen der Klasse und die enthaltenen Eigenschaften. Aus der Klasse erkennen wir wiederrum den Namen und den Typ der Klasse. Über das Field-Attribut der jeweiligen Eigenschaften kann der Name des Feldes in der SharePoint-Liste definiert werden, welcher sich auch vom Namen der Eigenschaft unterscheiden kann. Eine Listen- oder Feld-Definition besteht jedoch nicht nur aus dem Namen der Liste oder des Feldes und dessen Typ. Die Definitionen verfügen über viele weitere Eigenschaften, die festgelegt werden können. Um diese Eigenschaften definieren zu können, wurde das Field- und das List-Attribut um optionale Eigenschaften erweitert, über die das Feld oder die jeweilige Liste genauer bestimmt werden können.
Im der nächsten Abbildung sind alle Eigenschaften, die für ein Feld vordefiniert werden können aufgelistet:

 image 

Sämtliche Werte sind optional und werden, wenn benötigt mit einem Standardwert vordefiniert. Die für den Frontend-Benutzer relevanten Texte können in Deutsch und Englisch angegeben werden. Über das List-Attribute kann der Aufbau der Liste an sich genauer definiert werden, hierbei handelt es sich wie beim Field-Attribute um optionale Einstellungen, bei denen die für den Benutzer bestimmten Texte mehrsprachig hinterlegt werden können. Im Folgenden sind die optionalen Eigenschaften der Liste abgebildet:

image  

Aufgrund der Klassen-Struktur und der jeweiligen Attribute verfügen wir über alle Informationen, die wir benötigen um eine vollständige Struktur der Klassen in Form von Listen in SharePoint widerzuspiegeln. Aus diesen Informationen können nun alle benötigen Definitionen erzeugt werden, die benötigt werden um die entsprechenden Listen automatisiert in die Solution hinzuzufügen und in SharePoint anlegen zu können. Um das Erzeugen der Definitions-Dateien zu vereinfachen verfügt die Solutions2Share.Common über eine Komponente die diese Klassen-Struktur parst und in die entsprechenden XML-Dateien umwandelt. Diese Komponente wurde über eine VisualStudio-Erweiterung direkt in VisualStudio eingebunden und kann über das Contextmenü des SharePoint-Projektes aufgerufen werden:

 image

Nach dem Bestätigen des Menü-Punktes werden die sich in der VisualStudio-Solution befindlichen Assemblies geparst und die XML-Dateien der List- und Feld-Definitionen im SharePoint-Projekt erzeugt. Eine Abbildung der erzeugten Struktur der Definitions-Dateien für die oben aufgezeigte Klassen-Struktur ist im folgenden Bild aufgelistet.

image

Wie in Abbildung zu erkennen ist, wird für jede Business-Klasse ein ContentType angelegt, wobei hier auch die Vererbung der Klassen in der Vererbung der ContentTypes wiederspiegelt werden. Für jede Liste werden eine Definitions-Datei und ein Feature-Element zum Erzeugen einer Instanz der Liste erzeugt. Es wird nicht automatisch für jeden ContentType eine eigene Liste erzeugt, dies ist nur der Fall, wenn die ContentTypes nicht voneinander erben. Um die Vererbung der ContentTypes innerhalb einer einzelnen Liste zu ermöglichen werden alle ContentTypes als Site-ContentType und die Spalten der ContentTypes als Site-Column definiert. Bei der Erzeugung der Definitions-Dateien werden auch speziellere Typen wie Lookup- oder Choice-Felder berücksichtigt. Im Folgenden ist die Struktur der erzeugen Definitions-Datei auf Basis der ContractualPartner-Klasse abgebildet.

image  

In den Attributen der Klassen und Eigenschaften konnten die dem Benutzer angezeigten Texte mehrsprachig auf Deutsch und Englisch hinterlegt werden. Um in SharePoint die Texte mehrsprachig anzeigen zu können, müssen die Texte in Ressourcen-Dateien ausgelagert werden. In den Definitions-Dateien wird anstelle des eigentlichen Texts ein Verweis auf den Eintrag der Ressourcen-Datei eingetragen. Wie in der oberen Abbildung zu erkennen ist, ist z.B. beim Titel, der Url oder der Gruppe anstelle des eigentlichen Textes ein Ressourcen-Verweis eingetragen. Bei der Erstellung der Definitions-Dateien werden die Werte in den Ressourcen-Dateien automatisch erzeugt und gefüllt. Hier werden die Einstellungen aus den Attributen übernommen, bzw. der interne Name gesetzt, wenn kein Anzeige-Text in den jeweiligen Sprachen definiert wurde. Der Entwickler muss so nicht mehr selbst die Werte in den Ressourcen-Dateien erzeugen und füllen.
Ein Beispiel für die von der Solutions2Share.Common-Komponente erzeugten Ressourcen-Datei ist in der nächsten Abbildung zu sehen.

image

Wie in der Abbildung zu erkennen ist, werden die Ressourcen-Einträge nach einer einheitlichen Struktur dynamisch erzeugt.

Part IV: ExceptionHandling und Logging

Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Das Finden von Fehlern in SharePoint-Anwendungen ist oft verhältnismäßig schwierig. Vor allem bei Standardfehlermeldungen wie „Object reference not set to an instance of an object“ oder „Index out of range“. Das Eingrenzen dieser Fehlermeldungen ist häufig schwierig, weil sie praktisch überall innerhalb des Projektes auftreten können. SharePoint zeigt dabei nur eine allgemein Fehlermeldung bzw. zeigt nur den Text der Fehlermeldung. Das Log-File von SharePoint ist meistens sehr umfangreich und enthält zum anderen auch nichts weiter als die eigentliche Fehlermeldung. In vielen Fällen erhält man vom Kunden im Fehlerfall den Screenshot der Anwendung. Da auf dem Produktiv-System beim Kunden kein VisualStudio zum Debuggen installiert sein wird oder werden kann, sind bei umfangreicheren Projekten diese Fehlermeldungen schwierig auffindbar zu machen.

 clip_image002

In diesem Beispiel wird von einer Umfangreichen SharePoint-Anwendung ausgegangen, die aus sehr vielen relativ kleinen Funktionen und Methoden besteht. Initial wird ein Event, wie das z.B. Page_Load oder ein Event-Receiver aufgerufen, das wiederrum viele andere Methoden aufruft. Wie im Bild dargestellt ist, rufen diese Methoden wiederrum viele andere Methoden auf. In einer dieser Methoden tritt ein Standard-Fehler wie oben beschrieben auf, der behoben werden muss. In vielen Fällen muss dieser Fehler schnellst möglich behoben werden und es ist nur die Fehlermeldung an sich durch einen Screenshot verfügbar. Dies ist eine häufige Situation für den Entwickler, der zur Behebung des Fehlers nur über relativ wenige Informationen besitzt, wie dieser Fehler zustande gekommen ist. Um den Fehler beheben zu können, muss dieser vorher lokalisiert werden, was sich bei einem aus mehreren tausend Zeilen bestehenden Quellcode als schwierig erweisen kann. Da von einem Projekt ausgegangen wird, das aus vielen kleinen Methoden besteht, ist es als erstes wichtig zu wissen, in welcher dieser Methoden der Fehler aufgetreten ist. Für diese Fälle stellt die Solutions2Share.Common die Klasse ExceptionHandling bereit, welche wie folgt in jede Methode eingebaut wird: try { … } catch (Exception exc) { throw new ExceptionHandling(exc, MethodBase.GetCurrentMethod()); } Durch diesen Aufruf enthält die ExceptionHandling-Klasse die aktuelle Fehlermeldung und die exakte Methode, in der die Fehlermeldung aufgetreten ist. Die ExceptionHandling-Klasse baut die Fehlermeldung nun so um, dass vor der eigentlichen Fehlermeldung der komplette Pfad der Methode, in der die Exception aufgetreten ist, hinzugefügt wird. Im Page_Load muss nun nur noch die Fehlermeldung angezeigt werden und dem Entwickler ist, so wie im folgenden Beispiel, direkt ersichtlich in welcher Methode diese Fehlermeldung aufgetreten ist:

 clip_image002

In diesem Beispiel ist in der Klasse ExceptionWebPart im Namespace Solutions2Share.Common.Blog der eigentliche Fehler ist in der Methode GetListItems aufgetreten. Nach dem Pfad der Methode wird die eigentliche Fehlermeldung angezeigt. So ist für den Entwickler schon durch einen Screenshot ersichtlich, an welcher Stelle der Fehler aufgetreten ist.
In kleinen Funktionen kann die Exception so schnell lokalisiert werden, bei größeren Methoden, wie sie manchmal nicht zu vermeiden sind, kann in der ExceptionHandling-Klasse zusätzlich zur Methode noch ein Bezeichner für einen Abschnitt innerhalb der Methode angegeben werden. Dieser wird durch einen weiteren Punkt getrennt an den Pfad der Methode angehängt. So kann die Methode an sich in logische Abschnitte unterteilt werden. Auf diesen Weg kann schon durch einen simplen Screenshot die Fehlermeldung schnell lokalisiert werden, diese sind aber nicht immer verfügbar, wie z.B. bei TimerJobs oder EventReceivern. Hier bleibt es nur noch übrig in das Log-File zu schauen. Aber auch wenn die Fehlermeldung direkt dem Benutzer angezeigt wird, kann es im Nachhinein trotzdem hilfreich sein, diese nochmal im Log-File verfügbar zu haben. Wenn die Exception wie hier von der Applikation abgefangen wird, schreibt SharePoint von sich aus keine Einträge in das Log-File, was in vielen Fällen jedoch gewünscht ist. Um nicht nochmal zusätzlich im Fehlerfall in das Log-File schreiben zu müssen, wird diese Aufgabe direkt von der ExceptionHandling-Klasse verwendet. Diese schreibt standardmäßig über den ULS-Logger in das Log-File von SharePoint. Um die Logging-Routine nicht fest mit der ExceptionHandling-Klasse zu verknüpfen, bedient sich die Klasse des DependencyInjection-Pattern. Dafür wird dar ServiceLocator aus der Microsoft.SharePoint.Practices-Library verwendet. Microsoft bietet über die „Patterns & Practices“-Seite Richtlinien und Tipps zur Programmierung mit SharePoint an. Unter anderem werden auf dieser Seite .Net-Bibliotheken, wie die Microsoft.SharePoint.Practices und die Microsoft.Practices.ServiceLocation, angeboten.
Über den ServiceLocator wird eine Klasse definiert, z.B. der ApplicationLogger, der instanziert werden soll, wenn das Interface ILogger benötigt wird. Auf diese Weise holt sich die Application eine Instanz der Klasse ILogger, unabhängig davon, welche Klasse in der Application zu diesem Interface definiert wurde.
Dieses Verfahren wird von der ExceptionHandling-Klasse zum Schreiben der Log-Einträge verwendet.
Innerhalb der jeweiligen Application wird entsprechend die Logging-Klasse definiert, die ExceptionHandling-Klasse holt sich lediglich das Interface ILogger und schreibt über das Interface die Fehlereinträge in das entsprechende Log-File. In der Applikation muss lediglich definiert werden, welche Logging-Klasse vom ExceptionHandling verwendet werden soll. So bleiben ExceptionHandling und die eigentliche Applikation unabhängig voneinander.
Des Weiteren bietet die Solutions2Share.Common einige Helfer-Klassen u.a. zur Registrierung des Loggers in der jeweiligen Applikation.

Part III: VisualStudio – Templates

Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Die Solutions2Share.Common nimmt dem Entwickler bereits viel Routinearbeit ab und versucht häufige Fehler zu vermeiden bzw. das Auffinden der Fehler zu erleichtern, um dies alles Innerhalb eines Projektes zu ermöglichen sind noch ein paar kleine Anpassungen innerhalb des Projektes notwendig, wie z.B. die Bereitstellung der notwendigen projektspezifischen Klassen der Schichten-Architektur. Um auch diese Routinearbeit zu minimieren stellt Solutions2Share.Common VisualStudio-Vorlagen bereit, die diese Komponenten bereits implementieren bzw. automatisch erzeugt.

 image

Nach der Installation der VSIX-Datei stehen zwei neue Vorlagen in VisualStudio zur Verfügung:

  • Multilayer Small: Dies ist die VisualStudio-Vorlage für kleinere Projekte, hier wird eine VisualStudio-Solution mit einem einzelnen Projekt erstellt, in dem sich alle Dateien befinden.
  • Multilayer Big: Diese Vorlage ist für größere Projekte ausgelegt, hier wird für jede Schicht ein separates Projekt erzeugt. Die SharePoint-Solution stellt das Hauptprojekt der VisualStudio-Solution dar, Logic- und Data-Layer werden jeweils ein eigenes Projekt unterteilt.

Um die Namen der jeweiligen Elemente, wie z.B. den Namespace des Projektes oder die Namen der Klassen, im Projekt direkt bestimmen zu können, erscheint ein Dialog-Fenster in dem die Namen vordefiniert werden können:

image

Diese Bezeichner werden dann direkt in den Projekt-Dateien übernommen. Mit der Vorlage wird bereits die Standardstruktur der Ordner und Dateien mit dem Namen erzeugt.

image

Die für die Schichten-Architektur benötigten Dateien wurden bereits angelegt und entsprechend vorbereitet.

 image

Es wurden sowohl Namen der Dateien angepasst, als auch der Inhalt der Dateien mit dem benötigten Inhalt gefüllt .

image

Nach erstellen des SharePoint-Projektes auf Basis der Solutions2Share.Common-Vorlagen kann direkt mit der eigentlichen Umsetzung des Projektes begonnen werden, da durch die Vorlage alle benötigten Dateien bereits angelegt wurden.

Part II: Mapping zwischen Business-Objekten und SharePoint Listen

Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Wie bereits im ersten Artikel „MVC und Schichten-Architektur mit SharePoint“ beschrieben, kommunizieren die einzelnen Schichten der Architektur über Business-Objekte miteinander und haben somit außer dem Data-Layer keinen direkten Zugriff auf SharePoint. Unter einer Business-Klasse wird hier eine Klasse in C# verstanden, in der die Struktur einer SharePoint-Liste wiedergespiegelt wird. Dadurch wird ein typsicherer Zugriff auf die Werte aus der Liste gewährleistet, was im SharePoint-Standard so nicht möglich wäre, da die Werte intern als String hinterlegt und als Object zurückgegeben werden. Des Weiteren kann so die Applikation unabhängig von SharePoint mit den Daten arbeiten, was die Arbeit mit den Daten erleichtert, da z.B. über Linq direkt auf die Eigenschaften der Klasse zugegriffen werden kann. Durch die Trennung zwischen der Applikation und SharePoint verringert sich der Wartungsaufwand bei Änderungen an der Struktur der SharePoint-Liste bzw. die Änderungen können schneller übernommen werden, da der Compiler die Abweichungen sofort erkennt.

Ein Beispiel einer Business-Klasse kann wie folgt aussehen:
image

Diese Business-Klasse stellt einen Eintrag aus der Liste „Events“ innerhalb einer SharePoint-Site dar. Für jeden Eintrag der Liste wird eine neue Instanz, das so genannte Business-Objekt, der Klasse erzeugt und die Eigenschaften der Instanz aus den Werten des jeweiligen Listen-Elements befüllt. Die Instanzen sind serialisierbar und können somit als Text gespeichert werden, z.B. um sie im Cache zwischen zu speichern oder die Instanzen direkt über einen WebService übertragbar zu machen. Um die Eigenschaften der Business-Objekte mit den Werten aus des SharePoint-Elementen zu befüllen bzw. die geänderten Werte wieder in SharePoint speichern zu können, muss ein Mapping zwischen den Eigenschaften und den jeweiligen Spalten in der SharePoint-Liste existieren. Um das Lesen und Schreiben der Listen-Elemente in SharePoint zu realisieren, existiert die Hilfs-Klasse ContainerData<T>, die das Interface IContainerData<T> implementiert, wobei T die Business-Klasse darstellt.

image

Wie im Interface zu erkennen ist, können über dieses Interface die Listen-Elemente aus den SharePoint-Listen anhand der Business-Klassen ausgelesen und wieder in SharePoint gespeichert werden. Die Klasse selbst gibt nur Business-Objekte zurück bzw. nimmt diese entgegen, d.h. bei einer Abfrage auf die entsprechende Liste wird automatisch eine Liste der entsprechenden Business-Objekte zurückgegeben. Um dies zu realisieren ist keine Anpassung des Quellcodes durch den Entwickler notwendig, der Entwickler muss kein manuelles Mapping zwischen den Eigenschaften und den Spalten der Liste vornehmen, das Mapping wird automatisch über die ContainerData-Klasse abgewickelt.

image

Der Name des Feldes in der SharePoint-Liste wird über das Field-Attribut der jeweiligen Eigenschaft und dem Feld zugeordnet. So werden die Felder aus der Liste ausgelesen und die Eigenschaften gefüllt bzw. wieder in die Liste gespeichert. Eine manuelle Zuordnung ist nicht mehr notwendig. Innerhalb der Klasse wird der Name der Liste als Ressourcen-Eintrag hinterlegt. Die Liste wird automatisch anhand des Ressourcen-Eintrages aus der aktuellen SharePoint-Site ausgelesen. Die ContainerData-Klasse implementiert die Funktion: protected IEnumerable<T> GetItemsByQuery(string camlQuery, uint maxItems) Soll eine Benutzerdefinierte Caml-Query abgesetzt werden, kann diese über die GetItemsByQuery-Funktion abgesetzt werden. Es wird eine Liste der Business-Objekte zurückgegeben, die ListItems aus dem Ergebnis der Caml-Abfrage werden automatisch in die Objekte umgewandelt. Konstrukte wie diese werden dadurch nicht mehr benötigt: string firstName = Convert.ToString(listItem[“firstName”]); Sie sind nur nicht schlecht zu lesen, außerdem sind diese Konstrukte Fehleranfällig und aufwändig zu warten. Durch diese Methodik wird der Zugriff auf SharePoint über eine zentrale Stelle gehandelt. Ändert sich der Aufbau der SharePoint-Liste, wie z.B. der Name der Spalte, muss diese Änderung nur an einer einzelnen Stelle in der Business-Klasse übernommen werden und hat sonst keinerlei Auswirkungen auf die Applikation! So kann die Stabilität der Anwendung erhöht, Fehleranfälligkeit verringert und lästige Routinearbeit des Programmierers minimiert werden!

Part I: MVC und Schichten-Architektur mit SharePoint

Dieser Artikel ist Teil der Artikelserie “Solutions2Share.Common – Simplified/Standardised SharePoint Development”. Diese Serie beinhaltet 8 Kapitel.

Solutions2Share.Common
Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung

Die Solutions2Share.Common unterstützt den Entwickler bei der Kommunikation zwischen SharePoint und der eigentlichen Anwendung, wodurch Fehleranfälligkeit verringert und der Quellcode standardisierter werden soll. Die Kommunikation erfolgt über ein eine klassische Schichten-Architektur, wobei die direkte Kommunikation mit SharePoint, wie z.B. aus Schreiben und Lesen von Listen-Einträgen, nur im Data-Layer erfolgt. Die Kommunikation zwischen den Schichten selbst erfolgt ausschließlich über Business-Objekte, wobei nur eine unidirektionale Kommunikation zwischen den Schichten besteht, d.h. die übergeordnete Schicht erhält Zugriff auf die untergeordnete Schicht, aber nicht umgekehrt. Die untergeordnete Schicht wird niemals auf die übergeordnete Schickt zugreifen. Dabei besitzen alle Schichten denselben Kontext.

clip_image002
 

Der Data-Layer übernimmt die direkte Kommunikation mit dem SharePoint, d.h. sämtliche Listen-Zugriffe werden über diese Schicht abgewickelt, aber auch alle anderen Operationen wie z.B. das Setzen von Berechtigungen oder das Erzeugen von Ordnern. Im Data-Layer werden die Einträge aus den Listen und Bibliothek in Businessobjekte umgewandelt, wobei jeder Listeneintrag eine Instanz der jeweiligen Businessklasse darstellt. Eine Businessklasse spiegelt eine SharePoint-Liste typsicher wieder.
Die anderen Schichten kommunizieren ausschließlich über die jeweiligen Businessobjekte mit dem Data-Layer, Sie haben keinen direkten Zugriff auf SharePoint oder auf das ListItem in der Liste selbst. Der Data-Layer besteht aus mehreren einzelnen Modulen, viele Grundfunktionen von SharePoint werden bereits über unterschiedliche Module innerhalb der Solutions2Share.Common bereitgestellt. Hierbei wurden häufig die Aufrufe vereinfacht und das Fehlerhandling verbessert. Zusätzlich zu diesen Modulen kommen noch projektspezifischen Module, wie den Mapping-Modulen der Business-Klassen oder individuelle Module des Projektes hinzu. Der Logic-Layer bildet das Bindeglied zwischen der Präsentations- und der Daten-Schicht, hier werden sämtliche Operationen ausgeführt die keinen direkten Zugriff auf SharePoint benötigen, aber mit den Daten aus dem Data-Layer arbeiten. Auch der Logic-Layer kommuniziert nur über die Business-Objekte mit dem Presentation- und dem Data-Layer. Im Presentation-Layer, d.h. innerhalb des eigentlich WebParts oder der Layouts-Page, erfolgt die Darstellung der Daten, die als Business-Objekte vom Logic-Layer übertragen werden. Im Presentation-Layer wird der Context definiert, in dem die restlichen Schichten ausgeführt werden. Dadurch wird der Context an nur einer einzelnen Stelle und bis zu den unteren Schichten durchgereicht. Dadurch gibt es nur eine Stelle an der eine Änderung vorgenommen werden muss, wenn der Ausführungs-Context einer Operation geändert werden muss, weil dieser z.B. nicht mehr mit den Rechten des aktuellen Benutzers ausgeführt werden kann. Zusätzlich werden so die häufig auftretenden Security-Exceptions vermieden. Der Context kann so ohne Aufwand zwischen dem aktuellen Benutzer und dem „RunWithElevatedPrivileges“-Context gewechselt werden. Es ist für den Data-Layer nicht relevant, in welchem Context er ausgeführt wird, was die Fehleranfälligkeit und den Schreib-Aufwand verringert. Die Solutions2Share.Common stellt bereits Klassen zur Verfügung, um eine Schichten-Architektur zu realisieren. Die Klassen können als Basis für die Schichten-Architektur der Applikation verwendet werden. Um das Arbeiten mit den jeweiligen Schichten und dem Context zu erleichtern wird eine Factory bereitgestellt, die das Erzeugen der jeweiligen Objekte übernimmt. Im Presentation-Layer muss lediglich die jeweilige Funktion der Factory ausgeführt werden.

image
 

Alle Klassen der jeweiligen Schichten sind so ausgelegt, dass sie einfach erweitert werden können.

Solutions2Share.Common – Simplified/Standardised SharePoint Development

Einleitung

Wenn man bereits seit einigen Jahren als Entwickler in unterschiedlichen SharePoint-Projekten involviert ist, stellt man fest, dass sich die Anforderungen an den Entwickler und die Tätigkeiten während der Entwicklung sehr ähneln. Ein SharePoint-Projekt baut sich meistens aus denselben Komponenten, wie z.B. Einstellungs-Seiten oder XML-Dateien zur Definition von Listen usw. zusammen. Auch wenn sich die Anforderungen an das Projekt ändern, werden oft dieselben Funktionen und Komponenten benötig. Nachdem ich anfangs die Funktionen einfach von einem Projekt in das andere Projekt kopiert hatte, hab ich irgendwann angefangen diese zu sammeln um sie gemeinsam, ohne zu kopieren, verfügbar zu haben. Zuerst war dies nur eine einzelne Klasse mit einigen unzusammenhängenden Funktionen. Diese Klasse wurde damals schon in jedes Projekt eingebunden und war einem steten Wandel und auch einigen Namensänderungen unterzogen.
Aus dieser anfangs einzelnen Klasse mit einigen Funktionen ist im Laufe der Jahre die heutige Solutions2Share.Common entstanden. Die Solutions2Share.Common umfasst heute eine Vielzahl von Komponenten die dem Entwickler die tägliche Arbeit bei der Entwicklung von SharePoint-Projekten erleichtern und ihm notwendige Routinearbeit abnehmen sollen. So kann sich der Entwickler auf die eigentliche Aufgabe des Projektes konzentrieren, was neben der Effizienzsteigerung und der einfachen Zeitersparnis auch zur Zufriedenheit des Entwicklers beitragen kann.
Die Solutions2Share.Common besteht aus mehreren Komponenten, die für jeweils unterschiedliche Aufgaben zuständig sind. Die zentrale Komponente stellt hier die .Net-Bibliothek Solutions2Share.Common.dll dar, in der sich die zentralen Klassen und Funktionen befinden.

Autor

Christian Fluhrer Dieser Artikel wurden von Christian Fluhrer verfasst. Christian Fluhrer arbeitet als SharePoint Software Architekt und ist für die Entwicklung aller SharePoint Solutions im Unternehmen verantwortlich.

Xing: https://www.xing.com/profile/Christian_Fluhrer2
Website: http://www.cfluhrer.de/

Übersicht der Kapitel

Part I: MVC und Schichten-Architektur mit SharePoint
Part II: Mapping zwischen Business-Objekten und SharePoint Listen
Part III: VisualStudio – Templates
Part IV: ExceptionHandling und Logging
Part V: SharePoint-Definitionen automatisiert erstellen
Part VI: Dynamische Einstellungs-Seite
Part VII: Small Little Helpers
Part VIII: Verbesserung der Code-Qualität durch aspektorientierte Programmierung