Mittwoch, 25. Juni 2014

Speicher einer Generischen Liste in den Application Storage


Im letzten Post haben ich gezeigt wie wir eine Klasse in ein XML Serializieren und Deserializieren können, nun wollen wir unsere erzeugten XML Daten auch als StorageFile im Lokalen Applikation Verzeichnis Speicher.
 //Vergeben des Dateinamen
 string fileName = „TrackinData“;

 //Erzeugen des XML
 string localData = ObjectSerializer>.ToXml(list);
 if (!string.IsNullOrEmpty(localData))
 {
    //Erstellen der Datei und Speichern im Lokalen Verzeichnis
    StorageFile localFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(string.Format("{0}.xml", fileName), CreationCollisionOption.ReplaceExisting);
    await FileIO.WriteTextAsync(localFile, localData);
 }

Um die Daten wieder zu laden muss die Entsprechende Datei aus dem Lokalen Applikation Verzeichnis geladen werden und das erhaltene XML wieder Deserializieren werden.

  StorageFile localFile;
  ObservableCollection itemCollection = new ObservableCollection();
  Try
  {
      localFile = await ApplicationData.Current.LocalFolder.GetFileAsync("localData.xml");
  }
  catch (FileNotFoundException)
  {
      localFile = null;
  }
  
  if (localFile != null)
  {
      string localData = await FileIO.ReadTextAsync(localFile);
      itemCollection = ObjectSerializer>.FromXml(localData);
  }

Serializing / Deserializing objects in und aus einem XML


Zum Speicher und Austausch von Daten und Einstellungen greife ich gerne auf XML-Dateien zurück. Um diese zu erstellen habe ich bei http://www.getcodesamples.com/ eine recht elegante Lösung gefunden.

Mit Hilfe der ObjectSerializer Klasse kann man ganz einfach eine Klasse oder eine generische Liste in ein XML umwandeln.

ObjectSerializer Klasse
    internal static class ObjectSerializer
    {
        // Serialize to xml 
        public static string ToXml(T value)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            StringBuilder stringBuilder = new StringBuilder();
            XmlWriterSettings settings = new XmlWriterSettings()
            {
                Indent = true,
                OmitXmlDeclaration = true,
            };
            using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder, settings))
            {
                serializer.Serialize(xmlWriter, value);
            }
            return stringBuilder.ToString();
        }

        // Deserialize from xml 
        public static T FromXml(string xml)
        {
            T value;
            object empty = null;
            value = (T)empty;
            Try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                using (StringReader stringReader = new StringReader(xml))
                {
                    object deserialized = serializer.Deserialize(stringReader);
                    value = (T)deserialized;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);               
            }

Hierfür müssen in den zu Serializierenden Klassen XMLRootElemet Attribute gesetzt werden. Damit diese als root gekennzeichnet wird.


    [XmlRoot(ElementName = " XMLExampleClass ")]
    public class XMLExampleClass
    {

Entsprechend kann dann die Klasse unter Verwendung der Methode ToXml in ein XML Serializiert werde und mit der Methode FromXml wieder Deserializiert.

    XMLExampleClass instance = new XMLExampleClass();
    instance.Id = 0;
    instance.Name = “Test”

    // Serialize to xml 
    string localXml = ObjectSerializer.ToXml(instance);

   // Deserialize from xml
   XMLExampleClass instanceFromXml = ObjectSerializer.FromXml(localXml);

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;
        }