38E1CD914AB64900AE815E5B4FCB41E6
  • Stefan Buchali (UDG)
  • 22.01.2018
  • DE

C# im PreExecute: Tipps, Tricks und böse Fallen

Mit dem PreExecute gibt uns Opentext WSM eine wunderbare Funktion an die Hand, kann man doch hierdurch sämtliche Anforderungen, die das CMS mit seinen Bordmitteln nicht oder nur umständlich lösen kann, durch Nutzung einer beliebigen Server-Skriptsprache umsetzen.

„Beliebig“ ist zwar wörtlich gemeint. Da aber das CMS auf Microsoft .Net läuft, und der Server somit alle Voraussetzungen schon hat, bietet sich natürlich C# als PreExecute-Sprache an, denn dann ist keine weitere Installation oder Konfiguration der Maschine als solcher notwendig.

Ist PreExecute aktiviert, schaltet das CMS diesen Schritt in den Publishingprozess ein, und zwar vor Auslieferung der Seite an den Zielserver, aber nach Ausführung der Rendertags (siehe mein vorheriger Artikel Die RedDot-Reihenfolge). Dies ist wichtig zu beachten, denn dadurch kann man auf Daten und Werte, die durch Rendertags erzeugt wurden, zugreifen und diese weiterverarbeiten.
In umgekehrter Reihenfolge ist dies nicht möglich.

Kurz umrissen funktioniert der PreExecute so, dass die erzeugte Seite lokal auf Platte gelegt und dann per http aufgerufen wird. Hierbei wird sie durch den Webserver ausgeführt, der sich auf dem CMS-Server befindet. Das Ergebnis (fehlerfreie Ausführung vorausgesetzt) wird dann an den Zielserver übertragen.

Man büßt somit in SmartEdit, Vorschau und Publizierung etwas Performance ein, da dieser Prozess extra Zeit kostet. Letztendlich aber muss man das Gesamtsystem im Blick haben: Jede Funktion, die nicht auf dem Webserver bei jeder Auslieferung der Seite ausgeführt werden muss, sondern schon im CMS vorgeneriert (daher der Name „Pre-Execute“) werden kann, dient der Website-Performance.
 

Timeout

Da eine Publizierung erheblich Ressourcen beansprucht, benötigen andere Prozesse auf dem Server mehr Zeit als sonst, zu denen gehört auch der IIS. Aus diesem Grund sollte man den Timeout, den das CMS „ab Werk“ mit 10 Sekunden bemisst, großzügig erhöhen. 300 Sekunden sind hier ein ausreichend sicherer Wert.
 

Das .Net Caching

Ein wichtiger Punkt speziell bei Nutzung von .Net ist dessen eigenes Caching-Verhalten, bei dem jede ASPX-Datei nach ihrer ersten Ausführung in einem separaten Systemverzeichnis abgelegt wird.

Für herkömmliche Webapplikationen ist das sinnvoll, nicht aber für den PreExecute! Denn hier wird jede Datei ja nur einmal erzeugt, ausgeführt und dann wieder gelöscht. Die Kopie aber verbleibt im Caching-Verzeichnis, das sich nun stetig füllt.

Nach einiger Zeit finden sich dort Millionen von Dateien darin – und der Server wird immer langsamer, denn mit dieser Menge kommt Windows nicht klar.

Aus diesem Grund muss das Verzeichnis regelmäßig geleert werden (siehe Simply RedDot: "Slow CMS Due to .NET Preexecution").
 

Der Template-Grundaufbau

.Net ist deutlich strenger als es z.B. klassisches ASP (VB) war. Man kann hier nicht beliebig mit Variablen hantieren, sondern muss sie deklarieren und typisieren. Auch doppelte Deklaration ist nicht erlaubt. Diese kann jedoch bei OT-üblichen Container-Konstrukten schnell passieren, je nach dem wo sich die Deklaration befindet. Hierauf muss bereits zu Beginn eines neuen Projekts großes Augenmerk gelegt werden, damit man sich die Wartbarkeit und Erweiterungsfähigkeit nicht verbaut!

In unserem Unternehmen haben sich folgende Basisregeln etabliert und bewährt:

In den Masterpages selbst befindet sich ausschließlich die Deklaration:

<%@ Page language="c#" %>
<%cnt_global_preexecute_functions%>

Es folgt direkt ein Container namens „cnt_global_preexecute_functions“, der auf allen Seiten, die als Einzelseiten publiziert werden (also Masterpages, sowie Includes, per AJAX nachgeladene Schnipsel, etc), als Verweisvorbelegung vorhanden ist. In diesem Template werden zunächst die Imports definiert, je nachdem wie sie in dem Projekt benötigt werden. Beispiele sind

<%@ import namespace="System" %>
<%@ import namespace="System.Web" %>
…

Anschließend werden globale Funktionen definiert, die später von den einzelnen Templates verwendet und aufgerufen werden:

<script runat="server">
public string myFunction(string strInput) {
    /* ... */
    return strResult;
}
/* ... */
</script>

Zuletzt werden globale Variablen und Festlegungen deklariert. Sinnvoll sind hier z.B. die Abfrage nach Publizierungsmodus und der Projektvariante (STAGE, LIVE), anhand der später in den Templates je nach Modus und Variante unterschiedlicher Output erzeugt werden kann:

<% 
bool bolIsPublishMode = ("<%!! Context:CurrentRenderMode !!%>" == "2");
string strPvLive = "<%std_live_pv_guid%>";
string strPvCurrent = "<%inf_current_pv_guid%>";
string strPublishArea = (strPvCurrent == strPvLive) ? "live" : "test";
%>

Ebenso sollten hier Variablen deklariert werden, die in verschiedensten Templates z.B. als Schalter oder als Iteratoren fungieren können. Diese muss man dann im jeweiligen Template nur noch zurücksetzen, spart sich aber die Deklaration und die damit verbundenen Workarounds.

Müssen Variablen innerhalb eines Templates deklariert werden, dann ist zu beachten, dass Instanzen grundsätzlich mehrmals in einer übergeordneten Seite vorkommen können. Dem muss man Rechnung tragen, indem das gesamte Konstrukt in einen Scope gelegt wird. Gleiches gilt, wenn verschiedene Templates dieselben Variablennamen nutzen, was beispielsweise dann notwendig werden kann, wenn zwei Module ein und dasselbe Submodul nutzen.

Auch muss man frühzeitig festlegen, ob man um die gesamte Seite (also im Mastertemplate) einen einzigen großen PreExecute-Block setzt, oder ob man lieber mit kleinteiligen Schnipseln arbeitet. Letzteres hat positiven Effekt auf das CMS-interne Caching, birgt aber den Nachteil und die Gefahr, dass sich diese Blöcke je nach späterer Containerkonstruktion plötzlich verschachteln, was Projekt-Umbauten nach sich ziehen kann.
 

Fortgeschrittenen-Tipps

Das „Globale Funktionen“-Template sollte natürlich nicht in jedem Projekt neu angelegt werden, sondern global, also unter Nutzung des ContentklassenSharings zentral verwaltet.

Alternativ steht dieser Code gar nicht erst in einem CMS-Template, sondern wird, per GIT oder einem anderen Versionierungstool verwaltet, auf die CMS-Server deployt und von den Templates inkludiert.

Ganz Fortschrittliche dagegen können alle diese Funktionen auch als Custom Rendertags deklarieren und so im Optimalfalle vielleicht eines Tages komplett auf PreExecute verzichten!


Über den Autor:
Stefan Buchali (UDG)

Stefan Buchali ist Director Software Development bei der UDG United Digital Group. Seit dem Jahr 2001 betreut und entwickelt er zusammen mit seinem Team die Opentext- (vormals RedDot-) basierten Websites namhafter und internationaler Kunden.