Posts mit dem Label WCF werden angezeigt. Alle Posts anzeigen
Posts mit dem Label WCF werden angezeigt. Alle Posts anzeigen

Dienstag, 23. September 2014

Datenabruf aus Micorsoft Dynamics AX2012 R3 für eine Windows 8.1 App

Der Microsoft Dynamics AX2012 R3 bietet uns von hause aus schon einige Web Service mit deren Hilfe wir Daten aus dem AX konsumieren können. Hier bei möchte ich den QueryService Web Service hervorheben. Mit diesem lassen sich sowohl statische Querys aus dem AX ausführen als auch eigen Querys die in der Applikation definiert werden.

Hierdurch ist es uns möglich schnell und recht unkomplizierter Daten aus dem Microsoft AX 2012 R3 in einer App für Windows 8.1 oder Windows Phone 8.1 zu präsentieren.

hier ein kleines Beispiel für eine AX Query Ausführung:














 
Hier muss das benutzte Query jedoch im AX angelegt werden, was entsprechende AX Kenntnisse voraussetzt.

Alternativ können auch eigene Query in der Applikation erstellt werden, dies setzt dann eine Kenntnis der  Datenstriktur voraus.
 
Hier das Beispiel für eine solches Query:
 























 

Mittwoch, 16. Juli 2014

Erstellen einens einfachen REST Service

Im Grunde bezeichnet REST die Idee, dass eine URL genau einen Seiteninhalt als Ergebnis einer serverseitigen Aktion (etwa das Anzeigen einer Trefferliste nach einer Suche) darstellt.

REST setzt auf ein zustandsloses Client-Server-Protokoll, wobei im Normalfall HTTP oder HTTPS eingesetzt wird. Jede REST-Nachricht enthält dabei alle Informationen, die für den Server bzw. Client notwendig sind, um die Nachricht zu verstehen. Zustandslosigkeit wirkt sich begünstigend auf die Skalierbarkeit eines Webservices aus. Das ist natürlich genau das was wir für unsere Apps brauchen, etwas was schnell und einfach unsere App mit Daten füttert.
Und da die Daten als XML Ausgelesen werden, können wir diese REST Services sogar Plattformunabhängig nutzen.

Hier folgt nun ein kleines Beispiel für das erstellen eines REST Service. Dieser Service wird uns entweder eine Liste von Produkten oder über Parameter ein gewünschtes Produkt zurück geben. Wir betrachten somit nur den Lesenden zugriff über "GET"

1. Schritt eins Erstellen eines WCF Service Projekt

  • Starten Sie Visual Studio (im meinem Beispiel Visual Studio 2013)
  • Erstellen Sie ein neues Projekt vom Typ WCF-Dienstanwendung
Erstellen WCF-Dienstanweisung

2. Datenquelle für die Rückgabe erstellen

  • Für diese Beispiel erstellen wir ein einfache Klasse mit dem Namen Product.cs in der wir die Eigenschaften des Produktes erfassen können.

Des weiteren fügen wir eine Singelton-Klasse Namens Products.cs hinzu, von der wir die Methoden implantieren mit den wir an die Daten kommen wollen. Hier im Beispiel wird die Liste in einer einfachen Dummy Methode erstellt. Dies kann man natürlich auch gegen einen Datenbank Operation austauschen.


3. Erstellen des Service Contract

Fügen Sie Ihrem Projekt eine neues WCF-Dienst Element Namens ProductRESTService.svc hinzu.


Sie können die nicht benötigten Klasse Service1.svc, IService1.cs und Service1.cs gerne löschen. Beim hinzufügen werden sowohl die Service Klasse ProductRESTService.svc,  als auch der Service Vertrags als IProductRESTService.cs erstellt.

Im Service Vertrags als IProductRESTService.cs implementieren wir die Methode die über den Service zur Verfügung stehen sollen. Hierbei sollte der Namespace System.ServiceModel.Web eingebunden werden.


Das wichtige hierbei ist es zu die Nutzung des WebInvoke Attributes und seiner Parameter zu verstehen.
  • Method = "GET", stellt den HTTP GET Request da.
  • ResponseFormat  = WebMessageFormat.Xml, hier können wir zwischen XML oder JSON als Rückgabe Format auswählen.
  • BodyStyle = WebMessageBodyStyle.Bare, siehe WebMessageBodyStyle-Enumeration
  • UriTemplate ="GetProductById/{id}", siehe UriTemplate und UriTemplateTable 

4. Erstellen der REST Service Klasse

In der Service Klassen ProductRESTService.svs.cs müssen wir nun noch die im Service Vertrags definierten Methoden des Interfaces IProductRESTService implementieren und mit den jeweiligen Aufrufen bestücken.



5. Konfigurieren der Service

Was jetzt noch fehlt ist die Konfiguration des Dienst in der Web.config für einen REST Dienst wird das webHTTPBinding verwendet



6. Testen des REST Dienstes

Um den Dienst zu Testen können wir ihn  über einen rechst Klick auf die ProductRESTService.svs > Im Browser anzeigen (Internet Explorer) ausführen.
Die wird uns auch die Standard Dienst Seite leiten in der die Handhabung des Dienstes für WCF Clients beschrieben wir.
Wir wollen aber REST, das einzige was wir machen müssen ist die URL zu änderten und zwar mit dem jeweiligen Befehl des Service Vertrages:

http://localhost:54964/ProductRESTService.svc/GetProductById/3
 oder

http://localhost:54964/ProductRESTService.svc/GetProductList/

Dies sollte uns das gewünschte XML zurückgeben.

Und schon ist unser einfacher REST Dienst fertig. Viel Spaß bei selbst probieren und bis zum nächsten mal.

Dienstag, 10. Juni 2014

Verwende von AX2012 Query Service aus Windows Store App


Mit Hilfe des AX2012 Web Service QueryService können direkt aus einer App das Ergebnis eines Query des AOT verwendet werden ( siehe hierzu: http://technet.microsoft.com/en-us/library/gg847959.aspx ) leider habe ich in den ganzen Beispielen die es im TechLab oder MSDN gibt keins gefunden was auch für eine Windows Store App und Windows 8.1 funktioniert. Jedoch konnte man Auch hier schnell die Funktionen umschrieben um es unter Windows 8.1 als Store App zu Verwendern.

Hier ein kleines Beispiel mit deren Hilfe man zu Beispiel Bestands Informationen ermittelt kann. Ich verwende hierfür eine Hilfsklasse DynamicAXConnector mit deren Hilfe ich auch dynamisch die Endpoint Adressen der Web Service steuern kann.

Listing DynamicAXConnector:

namespace DynamicAXConnectorExampel
{
    public class DynamicAXConnector
         : IDisposable
    {
        #region Fields

        private string username = string.Empty;
        private string domainName = string.Empty;
        private string password = string.Empty;
        private string aosServer = string.Empty;
        private int port = 0;
        private WCFAdapters adapter;
        private AXQueryService.QueryServiceClient queryClient;

        #endregion

        #region Constructor

        public DynamicAXConnector(string username, string password, string aosServer, int wcfPort, WCFAdapters adapter)
        {
            this.aosServer = aosServer;
            this.adapter = adapter;
            this.port = wcfPort;
            this.password = password;

            string[] dom = username.Split('\\');
            if (dom.Length > 0)
            {
                this.domainName = dom[0];
                this.username = dom[1];
            }
        }

        #endregion

        #region Methods

        public async Task> GetInventSummary()
        {
            ObservableCollection ret = new ObservableCollection();
            try
            {
                EndpointAddress adr = this.NewEndPointAddress("QueryService", "DynamicsAx/Services/QueryService");
                this.queryClient = new AXQueryService.QueryServiceClient(AXQueryService.QueryServiceClient.EndpointConfiguration.QueryServiceEndpoint, adr);
                this.queryClient.ClientCredentials.Windows.ClientCredential.Domain = this.domainName;
                this.queryClient.ClientCredentials.Windows.ClientCredential.UserName = this.username;
                this.queryClient.ClientCredentials.Windows.ClientCredential.Password = this.password;

                AXQueryService.ExecuteStaticQueryRequest req = new ExecuteStaticQueryRequest();
                req.queryName = "ANXWin8InventSummary";
                req.paging = null;
                AXQueryService.ExecuteStaticQueryResponse res = await this.queryClient.ExecuteStaticQueryAsync(req);
                List list = res.ExecuteStaticQueryResult.Nodes;
                ret = BoInventSummary.FetchDataByQueryService(list, "ANXWin8InventSummary");              
            }
            catch (Exception)
            {
                throw;
            }

            return ret;
        }     

        public void Dispose()
        {
            this.client = null;
            this.response = null;
        }

        private EndpointAddress NewEndPointAddress(string addressHeader, string serviceName)
        {
            string uri = string.Empty;
            if (this.port == 0)
            {
                this.port = 8101;
            }

            switch (adapter)
            {
                case WCFAdapters.NetTcp:
                    uri = string.Format("net.tcp://{0}:{1}/{2}", this.aosServer, (this.port + 100).ToString(), serviceName);
                    break;
                case WCFAdapters.Http:
                    uri = string.Format("http://{0}:{1}/{2}", this.aosServer, (this.port + 100).ToString(), serviceName);
                    break;
                default:
                    break;
            }

            EndpointIdentity id = new SpnEndpointIdentity("");
            AddressHeader addressHeader1 = AddressHeader.CreateAddressHeader(addressHeader, uri, 1);
            AddressHeader[] addressHeaders = new AddressHeader[1] { addressHeader1 };

            return new EndpointAddress(new Uri(uri), id, addressHeaders);
        }

        #endregion
    }
}

In der Methode BoInventSummary.FetchDataByQueryService(list, ANXWin8InventSummary") wird das Objekt für die spätere DataSource aufbereitet und mit Werten gefütterte.      


 public static ObservableCollection FetchDataByQueryService(List list, string queryName)
        {
            ObservableCollection result = new ObservableCollection();
            foreach (XElement item in list.Elements(queryName).Elements("InventTable"))
            {
                BoInventSummary bob = new BoInventSummary();
                bob.ItemId = (string)item.Element("ItemId").Value;
                bob.Name = (string)item.Element("NameAlias").Value;
                foreach (XElement unit in list.Elements(queryName).Elements("InventTableModule"))
                {
                    bob.UnitId = (string)unit.Element("UnitId").Value;
                    break;
                }
                
                decimal physicalInvent = 0;
                decimal reservPhysical = 0;
                
                foreach (XElement sum in list.Elements(queryName).Elements("InventSum"))
                {
                    if (((string)sum.Element("ItemId").Value).Equals((string)item.Element("ItemId").Value))
                    {
                        physicalInvent += Convert.ToDecimal(sum.Element("PhysicalInvent").Value);
                        reservPhysical += Convert.ToDecimal(sum.Element("ReservPhysical").Value);
                    }
                }

                bob.PhysicalInvent = physicalInvent;
                .
                .
                .
                bob.ReservPhysical = reservPhysical;              
                result.Add(bob);
            }

            return result;
        }