Veröffentlichung von Microsoft Dynamics AX 2012

11. August 2011

Nun ist es soweit, dass warten auf die neue Version von Microsoft Dynamics AX 2012 ist vorbei. Der Realeas ist sogar früher erfolgt alls an anfänglich angekündigt. Nun können wir uns auf tolle Blogeinträge zum Thema AX 2012 freuen, denn es gibt sehr viel zu endecken. Im folgenden findet ihr den Link zur offiziellen Verkündung:

https://community.dynamics.com/b/theedge/archive/2011/08/01/drum-roll-please-microsoft-dynamics-ax-2012-is-now-on-the-market.aspx

Microsoft Dynamics AX News ,

Möglichkeiten der Objekthaltung in AX - Teil 1: Listen

29. Juli 2011

Ich habe mir gedacht es wäre ja ganz hilfreich wenn man mal eine Blog-Serie schreibt zum Thema: "Möglichkeiten der Objekthaltung".


Welche Möglichkeiten haben wir Objekte innerhalb von AX zu sammeln/speichern um diese eventuell an ein andere Methode zu übergeben. Klar wird der ein oder andere sagen: "mach es doch mit Übergabeparametern". Bei einer Übergabe, an eine Methode, bei einer Überschaubaren Anzahl von Objekten macht das sicherlich auch sin. Allerdings was ist, wenn wir diese Objekte, z.B. zur weiteren Verarbeitung, an weitere Methoden übergeben müssten? Oder wenn die Anzahl der Objekte noch garnicht fest steht.


Um so einen Fall abzudecken bietet AX verschiedene Möglichkeiten. Im folgenden eine Auflistung, welche Möglichkeiten ich euch in dieser Blog-Serie vorstellen möchte:

  • List
  • Container
  • Map
  • Temptable
  • Struct

 

In diesem Teil der Serie möchte ich euch die List etwas näher bringen. Der ein oder andere wird jetzt sicherlich denken: „ah Listen, ja kenne ich“. Dem möchte ich nicht zwangsläufig wiedersprechen allerdings funktionieren die Listen in AX etwas anderes. Sie sind nicht so komfortabel wie man es z.B. aus C# kennt.


Fangen wir erst einmal an, eine List zu erzeugen. Eine List erzeugt man wie folgt:

static void ListTestJob(Args _args)
{
    List            myList = new List(Types::String);
    ;
}

 

Nun erzeugen wir einfach drei Variablen und fügen diese unsere Liste hinzu. Der Quellcode wurde wie folgt erweitert:

static void ListTestJob(Args _args)
{
    List            myList = new List(Types::String);
    str             firstString;
    str             secondString;
    str             thirdString;
    ;

    firstString     = 'erster String';
    secondString    = 'zweiter String';
    thirdString     = 'dritter String';

    myList.addEnd(firstString);
    myList.addEnd(secondString);
    myList.addEnd(thirdString);
}

 

Jetzt haben wir drei String-Objekte in unsere Liste. Bleibt die Frage wie komme ich jetzt wieder an meine Objekte? An sich ganz einfach, wir bedienen uns der Listenumerator-Klasse aus AX, um unsere Objekte aus der Liste auszulesen. Dazu erzeugen wir ein ListEnumerator-Objekt und weisen diesem Objekt die Referenzen aus unserem Listenobjekte zu. Der folgende Code zeigt wie das im Code aussieht:

static void ListTestJob(Args _args)
{
    List            myList = new List(Types::String);
    ListEnumerator  myListEnum;
    str             firstString;
    str             secondString;
    str             thirdString;
    ;

    firstString     = 'erster String';
    secondString    = 'zweiter String';
    thirdString     = 'dritter String';

    myList.addEnd(firstString);
    myList.addEnd(secondString);
    myList.addEnd(thirdString);

    myListEnum = myList.getEnumerator();
}

Jetzt können wir mit einer While-Schleife durch unser Objekt iterieren und jedes Objekt aus der Liste lesen bzw. verändern. Der Folgende Code zeigt wie man mit der Methode current() an das aktuelle Objekt kommt und dieses dann per Info ausgibt:

while(myListEnum.moveNext())
    {
        {
            info(myListEnum.current());
        }
    }


Da es leider keine Möglichkeit gibt ein Objekt direkt per Index zu bekommen, muss man einen kleinen Umweg gehen um an das gewünschte Objekt zu kommen. Man erzeugt sich eine Zählervariable, die dazu dient eine If-Bedingung zu erfüllen. Diese If-Bedingung wird dann so konzepiert, dass sie einem das gewünschte Objekt zurückgibt. Wie das aussehen kann zeigt dieser Quellcode:

static void ListTestJob(Args _args)
{
    List            myList = new List(Types::String);
    ListEnumerator  myListEnum;
    str             firstString;
    str             secondString;
    str             thirdString;
    int             i = 0;
    ;

    firstString     = 'erster String';
    secondString    = 'zweiter String';
    thirdString     = 'dritter String';

    myList.addEnd(firstString);
    myList.addEnd(secondString);
    myList.addEnd(thirdString);

    myListEnum = myList.getEnumerator();

    while(myListEnum.moveNext())
    {
        if(i == 1)
        {
            info(myListEnum.current());
        }
        i++;
    }
}

 

Wie erwartet gibt uns der obige Quellcode nun eine Info aus mit dem Stringvalue "zweiter String".

 

Was noch hilfreich ist wenn man in AX mit Listen arbeitet, ist die Möglichkeit die komplette Anzahl aller Objekte in der Liste zu erhalten. Mit der Methode elements kann dieses erreicht werden. Mit folgendem Code kann über Info die Anzahl der Liste ausgegeben werden:

info(int2str(myList.elements()));

 

Weiter Infos zum Thema Listen findet ihr direkt über MSDN auf folgenden Links:

http://msdn.microsoft.com/en-us/library/aa498818%28v=ax.50%29.aspx

http://msdn.microsoft.com/en-us/library/aa848905%28v=ax.50%29.aspx

 

Den Quellcode als XPO bekommt ihr hier:

ListTestJob.xpo (1,19 kb)

Dynamics AX ,

Drei Schichten Modell mit LightCore

23. Februar 2011

Als Änfänger fragt man sich immer:

"Wie baut man am besten die Struktur eines Programmes auf?".

Die Frage ist nicht auf Anhieb zu beantworten, da es immer von der Anforderung des zu erzeugenden Programmes abhängt, wieviele und welche Schichten man benötigt. Für weitere Informationen könnt ihr euch hier informieren. Ich möchte nun näher auf das drei Schichten-Modell in Kombination mit LightCore eingehen. Im folgenden eine Grafik, die das Ganze mal etwas verdeutlicht:

Wie man in der Grafik gut erkennen kann, sind die Schichten nur in direkter Richtung zueinander verbunden. Das hat so auch seine Richtigkeit, da z.B. die GUI nicht auf Inhalte des DataLayers zugreifen soll. Der Weg ist also klar vorbestimmt: von der GUI zum BusinessLayer und von dort zum DataLayer. In der Core-Schicht werden die einzelnen Interfaces für die jeweiligen Layer abgelegt.

Da wir hier eine mehrschichtige Architektur haben, ist es wünschenswert, dass die Abhängigkeiten untereinander so gering wie möglich gehalten werden. Das hat später den Vorteil, dass man ohne viel Aufwand einfach eine Schicht gegen eine andere austauschen kann. Genau an diesem Punkt kommt LightCore zum Tragen. LightCore ist ein sogenannter Inversion of Control Container (IoC Container), der auch in der Core-Schicht abgelegt wird. Weitere Informationen zum Thema IoC findet ihr hier. Inizialisiert wird er bei dem oberen Beispiel in der GUI. Im IoC werden alle Interfaces regestriert, damit man später auf die Objekte zugreifen kann. Wie das im Einzelnen geht, zeige ich später noch.

Durch diese Initialisierung muss allerdings eine Referenz auf den DataLayer eingerichtet werden, da sonst der DataLayer nicht abgedeckt ist. Somit liegt eine flexible drei Schichten Architektur vor. Nachfolgend eine Änderung im Schichtenmodell - links das Modell was wir schon kennen, rechts sieht man eine strenge drei Schichten Architektur.

Hinzugekommen ist in der neuen Variante die Schicht namens Framework. In dieser Schicht kann nun der IoC Container initialisiert werden, da Framework Referenzen auf alle Schichten hat. Soweit die Theorie, kommen wir nun zur Umsätzung innerhalb von Visual Studio. Das Schichtenmodell habe ich in Visual Studio wie folgt umgesetzt:

Wie weiter oben schon erwähnt, wurde eine Referenz im Core Layer auf die LightCore Assambly hinzugefügt. Weiterhin wurde eine Klasse mit dem Namen IoCContainer erstellt. Im IoCContainer werden alle Interfaces durch eine Regestrierung in der Klasse Initializer, die zur layerübergreifenden Kommunikation notwendig sind, gespeichert. Hier der Code der IocContainer-Klasse:

public class IocContainer
    {
        private static readonly ContainerBuilder _builder;
        private static IContainer _container;

        static IocContainer()
        {
            _builder = new ContainerBuilder();
        }

        public static void Register<TContract, TImplementation>() where TImplementation : TContract
        {
            _builder.Register<TContract, TImplementation>();
        }

        public static T Get<T>()
        {
            return _container.Resolve<T>();
        }

        public static void Build()
        {
            _container = _builder.Build();
        }
    }

 

Im folgenden noch die Klasse Initializer:

public class Initializer
    {
        public static void Initialize()
        {
            IocContainer.Build();
        }
    }

 

Ein geeigneter Ort um den IocContainer zu initialisieren ist der Standardkonstrukter in der starter Klasse auf der Form. In diesem Fall ist das die GUI und somit die Klasse MainWindow.xaml.cs.

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            // IoC Container erstellen
            Initializer.Initialize();

            InitializeComponent();
        }
    }

 

Da wir jetzt das Grundgerüst unseres Programmes haben, zeige ich euch wie man eine neue Instanz einer Klasse erzeugen kann ohne den "new" Operator zu benutzen. Als erstes erzeugen wir auf dem CoreLayer einen Unterordner mit den Namen Contracts, darin errzeugen wir dann ein neues Interface. In meinem Beispiel nenne ich das Interface IanyRepository.

 

Jetzt implementieren wir das Interface auf dem DataLayer. Dazu erzeuge ich eine neue Klasse mit dem Namen AnyRepository auf dem DataLayer mit folgendem Inhalt:

public class AnyRepository : IanyRepository<string>
    {
        public List<string> getAny()
        {
            throw new NotImplementedException();
        }
    }

 

Da ich die Klasse mit der Methode getAny nur zu Testzwecken erzeugt habe, wird hier auch kein weiterer Code ausgeführt oder ein Wert zurückgegeben. Für die Demonstration des Beispiels ist das auch nicht weiter von Nöten.

Damit wir später eine neue Instanz erzeugen können, muss das Interface nun mit der dementsprechenden Klasse im IoCContainer regestriert werden. Dazu ergänzen wir die Klasse Initializer mit folgendem Code:

public class Initializer
    {
        public static void Initialize()
        {
            IocContainer.Register<IanyRepository<string>, AnyRepository>();
            IocContainer.Build();
        }
    }

 

Zur Demonstration habe ich eine weitere Klasse auf dem BusinessLayer mit dem Namen AnyClass und folgendem Code erzeugt:

public class AnyClass
    {
        IanyRepository<string> repository = IocContainer.Get<IanyRepository<string>>();

        public void AnyMethode()
        {
            List<string> liste =  repository.getAny();
        }
    }

 

Jetzt kann man sehen, dass ich in Zeile drei eine neue Instanz der Klasse AnyRepository erzeugt habe. In Zeile sieben greife ich dann auf die Instanz zu und rufe die Methode getAny, die als Rückgabewert eine Liste mit dem Typ string zurück gibt, auf. Wie jetzt gut zu sehen ist, wurde das Ganze ohne den Operator new erreicht.

Ein weiterer Vorteil dieser Methode ist, dass man in der Klasse Initializer eine andere Klasse, die z.B. Beispielwerte zurückgibt (Mock-Klasse), ganz einfach mit dem gleichen Interface regestrieren kann. Beim Aufruf wird dann die Mock-Klasse aufgerufen und nicht die Klasse die später einmal vorgesehen ist. Zur Veranschaulichung hier noch ein Beispielcode aus der Klasse Initializer:

public class Initializer
    {
        public static void Initialize()
        {
            // Ursprünglicher aufruf der Klasse AnyRepository
            //IocContainer.Register<IanyRepository<string>, AnyRepository>();

            // Jetziger aufruf
            IocContainer.Register<IanyRepository<string>, MockAnyRepository>();
            IocContainer.Build();
        }
    }

 

Damit ihr selber herum experementieren könnt füge ich das Projekt als Download hinzu:

TierThreeModelDemo.rar (231,31 kb)

C# ,

Microsft SQL Server Error 18452

20. Februar 2011

Als Neuling kann es schon recht verwirrend sein, diese Fehlermeldung beim Verbinden auf die Datenbank über SQLServer Manager bzw. über ein externes Script/Website zu bekommen:

Als Grundlage setze ich Voraus, dass man schon eine Datenbank angelegt hat, der Datenbank einen Benutzer zugeteilt und die Rechte soweit vergeben hat. Will man nun von extern auf die Datenbank zugreifen, wird man abgewiesen. Über den SQLServer Manager bekommt man zwar eine Verbindung, allerdings nur über die Windows Authentification und nicht über die SQL Server Authentification. Die Lösung des Problems ist recht einfach und schnell umgesetzt:

Hat man den SQLServer mit den Standardeinstellungen installiert, ist die SQL Server Authentification deaktiviert, genauso wie das "sa" Konto. Beides wird allerdings benötigt, um eine Verbindung von außerhalb herzustellen. Logt euch über die Windows Authentification auf die Datenbank ein und geht in die Eigenschaften der Datenbank.

Geht nun in dem folgenden Fenster auf Security und wählt die Option SQL Server und Windows Authentification mode aus. Das Ganze hinterher mit ok bestätigen.

Nun geht ihr auf den Knoten Security->Logins und macht einen Doppelklick auf den "sa" Benutzer.


In dem folgenden Fenster vergebt ihr nun ein neues Passwort und klickt anschließend auf Status.

Im Bereich Login setzt ihr jetzt den Punkt bei Enabled und bestätigt das Ganze mit ok.


Jetzt noch den SQLServer neustarten und euer Problem sollte gelöst sein.


.Net Allgemein ,