Dynamics AX Blog - Microsoft Dynamics AX (Axapta) - Seite 30

In den letzten Jahren, in denen ich mich fast hauptsächlich mit der Entwicklung im Umfeld von Microsoft Dynamics AX (vormals Axapta) beschäftigt habe, ist das eine oder andere Code-Fragment entstanden, von dem ich mir vorstellen könnte, daß es auch für andere AX-Entwickler ganz nützlich sein könnte. Aber auch Tips und Tricks zu dem mächtigen ERP-System werde ich in dieser Kategorie präsentieren.
RSS-Feed dieser KategorieAX 2012: Beispiel für die Verwendung des SysOperation-Frameworks
04.11.2012Microsoft Dynamics AX (Axapta)
|
AX 2012: SysOperation-Framework: Werte eines Data Contracts prüfen
02.11.2012Microsoft Dynamics AX (Axapta)
Wenn man in einem Data Contract die Klasse SysOperationValidatable über den Befehl implements einbindet, kann man die dadurch zur Verfügung stehende Methode validate() einbinden. Mit Hilfe dieser Methode können bereits bei der Eingabe von Werten im - beispielsweise vom SysOperation-Framework - generierten Dialog Prüfungen durchführen. Die Methode funktioniert ähnlich wie die gleichnamige Methode des RunBaseBatch-Frameworks. [DataContractAttribute]
class TutorialSysOperationDataContract implements SysOperationValidatable { date dialogDate; }
[DataMemberAttribute]
public TransDate parmDialogDate(TransDate _dialogDate = dialogDate) { dialogDate = _dialogDate; return dialogDate; }
public boolean validate()
{ boolean ret; ret = true; // Simple validation example if(this.parmDialogDate() && this.parmDialogDate() < systemDateGet()) { ret = checkFailed(strFmt("'%1' has to be greater/equal than %2.", "@SYS128676", systemDateGet())); } return ret; }
|
AX 2012: SysOperation-Framework: Werte eines Data Contracts initialisierenWenn man in einem Data Contract die Klasse SysOperationInitializable über den Befehl implements einbindet, kann man die dadurch zur Verfügung stehende Methode initialize() einbinden. Mit Hilfe dieser Methode kann man Variablen innerhalb des Data contracts initialisieren. Diese Methode wird allerdings nur aufgerufen, solange keine Nutzungsdaten gefunden werden bzw. diese nicht aktiviert sind. [DataContractAttribute]
class TutorialSysOperationDataContract implements SysOperationInitializable { date dialogDate; }
[DataMemberAttribute]
public TransDate parmDialogDate(TransDate _dialogDate = dialogDate) { dialogDate = _dialogDate; return dialogDate; }
public void initialize()
{ dialogDate = systemDateGet() - 365; }
|
AX 2012: SysOperation-Framework: Titel des Dialoges ändern
20.10.2012Microsoft Dynamics AX (Axapta)
Als Titel eines vom SysOperation-Framework generierten Dialoges wird in der Regel der Label des aufrufenden MenuItems angezeigt. Möchte man diesen Titel bewusst übersteuern, so muss man in der Service Controller Class (=abgeleitet von SysOperationServiceController) die nachstehenden beiden Methoden einbinden/überschreiben: public LabelType parmDialogCaption(LabelType _dialogCaption = '')
{ // Base class is setup to get the caption from the // the class name or from the menu item. Reroute it // to the caption override. return this.caption(); }
public ClassDescription caption()
{ ClassDescription ret; ret = "Tutorial-SysOperation-Framework"; return ret; }
|
AX 2012: SSRS: Einen Parameter einrichten
26.09.2012Microsoft Dynamics AX (Axapta)
In einem anderen Beitrag habe ich beschrieben, wie man beispielsweise einen SSRS-Report auf Basis eines Dataproviders erstellt. Dieser Beitrag ist quasi eine Fortsetzung in dem im demonstrieren möchte, wie man einen Parameter erstellt. Ein solcher Parameter ist einerseits notwendig, wenn man den Bericht als Subreport verwenden möchte oder aber auch wenn man Funktionalitäten abbilden möchte, die über den Dataprovider nicht abgebildet werden können. Im folgenden Beispiel soll der Bericht auf Basis eines Parameters so eingeschränkt werden können, sodaß Zeilen ohne Relevanz (im konkreten Fall Artikel, die noch nicht innerhalb einer Auftragsposition verwendet wurden) ausgeblendet werden können.
Schritt 1: Erstellen des Parameters |
Fehlermeldungen temporär übersetzen
08.09.2012Microsoft Dynamics AX (Axapta)
Kurzer Tipp zum Thema Fehleranalyse während des Entwickelns: Oft treten in Dynamics AX Fehlermeldungen auf, die auf den ersten Blick nicht verständlich sind und eine Suche nach beispielsweise deutschprachigen Fehlermeldungen im Internet ist oft nicht erfolgreich. Mit Hilfe des nachstehenden Jobs kann man einfach kurzfristig die Ausgabesprache des InfoLogs ändern - z.b. auf en-us - um anschließend mit der englischsprachigen Fehlermeldung eine möglicherweise erfolgreichere Internetrecherche anzustossen. static void changeInfologLanguage(Args _args) { infolog.language("en-us"); } Danach nur nicht vergessen, die Sprache wieder zurückstellen ;-) |
AX 2012: SSRS: Einen Bericht auf Basis eines Dataproviders erstellen
05.09.2012Microsoft Dynamics AX (Axapta)
Ein Dataprovider ist eine Klasse, die dazu verwendet wird um Daten für die Verwendung durch die SQL Reporting Services (SSRS) aufzubereiten. Ein solcher Dataprovider ist in jenen Fällen sehr hilfreich, wenn die anzuzeigenden Daten nicht - oder nur sehr mühsam - über einen Query ermittelt werden können. Im folgenden eine Schritt-für-Schritt Anleitung, wie man einen solchen Dataprovider erstellt und in den SSRS verwendet.
Schritt 1: Klasse erstellen, abgeleitet von SRSReportDataProviderBaseclass DmoSalesLineCountDataProvider extends SRSReportDataProviderBase
{ DmoSalesLineCountTmp DmoSalesLineCountTmp; } |
|
|
|
|
|
|
Das SysOperation-Framework ist eine Neuerung in Dynamics AX 2012 und soll das RunBasebatch-Framework ersetzen. In der MSDN sind zahlreiche Dokumentationen und Whitepaper über dieses Framework zu finden, welche ich unbedingt empfehle zu lesen.
Der folgende Beitrag enthält ein bewusst einfach gehaltenes Beispiel, wie man in AX 2012 Programmlogik auf Basis dieses Framework einsetzen kann.
Das Beispiel besteht dabei aus insgesamt vier Klassen:
Data Contract Class
Eine Data Contract Class besteht im Grunde genommen lediglich aus Accessor-Methoden (parm...-Methoden) und ist dadurch gekennzeichnet, daß in der classDeclaration() das Attribute DataContractAttribute verwendet wird.
Für alle Accessor-Methoden des Data Contracts werden vom SysOperation-Framework beim Aufruf entsprechende Dialogfelder generiert.
DIe weiteren im Beispiel verwendeten Attribute SysOperationContractProcessingAttribute bzw. SysOperationGroupAttribute verknüpfen zum Einen den Data Contract mit einem UI Builder und zum Anderen wird - neben der standardmässig immer generierten Feldgruppe namens Parameter - eine weitere Feldgruppe mit dem internen Namen DemoGroup.
Accessor-Methoden eines Data Contracts müssen immer über das Attribute DataMemberAttribute gekennzeichnet werden. Das Attribute SysOperationDisplayOrderAttribute legt die Reihenfolge der Felder im Dialog fest und mit Hilfe des Attributes SysOperationGroupMemberAttribute wird gesteuert, daß das Feld innerhalb der in der classDeclaration() definierten Feldgruppe eingeordnet wird.
Die Accessor-Methode für das Datum unterscheidet sich im groben nur durch ein weiteres verwendetes Attribute SysOperationLabelAttribute mit Hilfe dessen das Label des Dialogfeldes festgelegt wird.
Das hier anzugebende Datum ist im übrigen lediglich zu Demonstrationszwecken implementiert und hat keinen erwähnenswerten Einfluss auf die Programmlogik.
In der Accessor-Methode für den Dateinamen wird über das Attribute SysOperationDisplayOrderAttribute festgelegt, daß das Feld das Erste im Dialog sein soll.
Eine Besonderheit unter den im Beispiel verwendeten parm-Methoden stellt die folgende Methode dar. Weil innerhalb von Accessor-Methoden nicht jeder in AX zur Verfügung stehender Datentyp verwendet werden kann, muss ein Query beispielsweise in einen String umgewandelt und übergeben werden. Das SysOperation-Framework stellt dafür eigene Methoden zur Verfügung.
Die Methode validate() steht nur zur Verfügung, wenn in der classDeclaration() des Data Contracts die Klasse SysOperationValidatable eingebunden wurde. Dann funktioniert sie ähnlich, wie im RunBaseBatch-Framework.
Die Methode initialize() steht nur zur Verfügung, wenn in der classDeclaration() des Data Contracts die Klasse SysOperationInitalize eingebunden wurde. Diese Methode wird nur aufgerufen, wenn keine Nutzungsdaten vorhanden oder verwendet werden.
Service Class
Diese - von SysOperationServicebase abgeleitete - Klasse, enthält die eigentliche Logik des Beispiels.
Genauergesagt ist die Logik in der Methode runService() enthalten. Die Besonderheit dieser Methode ist, daß sie als einzigen Parameter den Data Contract erhält und daß das Attribute SysEntryPointAttribute gesetzt ist. Der Name der Methode hingegen bleibt dem Entwickler überlassen, die Methode wird über den Namen in der Methode newFromArgs() des Service Controllers referenziert.
Die im Beispiel enthaltene Methode enthält keine aufregende Logik, sie erstellt ledigich eine einfache Text-Datei und schreibt in diese einige Werte aus den über den Query übergebenen Ausgangsrechnungen.
Controller Class
Eine Controller Class muss von SysOperationServiceController abgeleitet sein.
Die Methode newFromArgs() ist eine selbst erstellte Methode, die dazu dient, die Klasse zu instanziieren. Dabei wird die Klasse und die als Service aufzurufende Methode festgelegt. Gleichzeitig wird über die Methode parmArgs() des Frameworks der Aufrufer für einen evtl. späteren notwendigen Zugriff gespeichert.
Die initQuery() dient dazu, den Query für den Dialog zu initalisieren. Diese Methode wird später von der Methode initializeServiceParameter() aufgerufen.
Erwähnenswert ist in Verbindung mit dem Query die Klasse SysOperationHelper, die u.a. Methoden zur Verfügung stellt, um einen Query in einen String zu konvertieren und umgekehrt. Dies ist notwendig, da der Data Contract nur mit "einfachen" Datentypen arbeiten kann.
Wie zuvor angekündigt, verwende ich die Methode initializeServiceParameter() um den Query des Dialoges über die Methode initQuery() zu initalisieren. Weiters wird an dieser Stelle ein weiterer Parameter mit Werten befüllt.
Die main()-Methode ist bereits aus dem RunBaseBatch-Framework hinreichend bekannt. Sie wird immer dann aufgerufen, wenn die Controller Class über ein MenuItem aufgerufen wird.
In dieser Methode wird - über die oben erwähnte Methode newFromArgs() - die Klasse instanziiert. Weiters wird über parmExecutionMode() der Ausführungsmodus festgelegt und schließlich über startOperation() der eigentliche Aufruf des Service gestartet.
Diese Methode retouniert übrigens einen Enum-Wert vom Typ SysOperationStartResult mit Hilfe dessen man abfragen kann, ob das Service beispielsweise sofort oder im Stapel gestartet wurde oder ob der Dialog vom Benutzer abgebrochen wurde.
UI Builder Class
Eine User Interface Builder Class ist dadurch gekennzeichnet, daß sie von SysOperationAutomaticUIBuilder abgeleitet ist. Eine solche Klasse kann dazu verwendet werden, den vom Framework automatisch generierten Dialog um eigene Logik zu erweitern.
Die Verknüpfung zwischen Data Contract und UI Builder erfolgt dabei über das Attribute SysOperationContractProcessingAttribute in der classDeclaration() des Data Contracts.
Ein Ziel unserer UI Builder Class ist, das Lookup-Formular des Feldes für das Debitorenkonto zu übersteuern. Dazu erstellen wird eine neue Methode beliebigen Namens - im Beispiel custAccount_lookup() - und befüllen diese mit dem gewünschten Programmcode. Im Grunde genommen unterscheidet sich die Methode nicht von anderen, ähnlichen Lookup-Methoden. Das einzige worauf man achten muß ist, daß die Methode die gleichen Parameter enthält, wie die gleichwertige Methode eines Formulares.
Die Methode postBuild() ist ein idealer Platz, um die in der classDeclaration() deklarierte Variable vom Typ DialogField über bindInfo().getDialogField() mit Leben zu befüllen.
Auch ist die Methode gut dazu geeignet, die Eigenschaften von Dialogfelder abhängig vom Aufrufer zu übersteuern. Im Beispiel wird dazu die Methode parmArgs() des Service Controllers abgefragt.
In der Methode postRun() kann man nun das Dialogfeld mit der oben beschriebenen Lookup-Methode verbinden.
Menu Item
Als letzten Schrittt gilt es nun ein MenuItem für die Service Controller Class zu erstellen. Ruft man dieses MenuItem auf, so sollte sich das oben beschriebene Beispiel wie folgt im Client darstellen: