VaMoS 2012 Paper: Managing variability of ERP ecosystems

The paper is about variability in ERP ecosystems, especially the situation of Dynamics AX partner companies. We present an idea how partner companies could manage the variability in their solutions to set up a product line. The paper can be found at the ACM Digital Library

Use Fulltext Index in AX 2012 to search in RSS feeds

Here is a simple example how to use the fulltext index capability in Dynamics AX 2012. This example downloads RSS postings into a table with fulltext index and runs a query to identify those with specific words.

Create the RssFeedTable

  1. Create a new String Extended Datatype called RssFeedId
  2. Create a new table called RssFeedTable and add the RssFeedId, Name and Uri
  3. Create a primary index based on the RssFeedId
  4. Set the RssFeedTable as Reference at the RssFeedId Extended
  5. Populate the table with data e.g.
    FeedId = technet
    Name = “Technet Austria”
    Uri = http://feeds.feedburner.com/TechnetTeamBlogAustria?format=xml

Create the RssContentTable

  1. Create a new Table called RssContentTable
  2. Add the RssFeedId, Description255 and rename it as Title and a Memo field
  3. Create a fulltext index for the memo field

image image

    Create the RSS Reader Class in C#

    1. Create a new Visual C# class library project for .NET 4.0 in Visual Studio
    2. Add the project to AOT
    3. Copy this code

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel.Syndication;
    using System.Xml;
    using System.Text.RegularExpressions;

    namespace ErpCoder.RssFeed
    {
        public class Reader
        {
            private string xmlAddress = String.Empty;
            private IEnumerator<SyndicationItem> enumerator;

            public Reader(string address)
            {
                xmlAddress = address;
            }

            public void Load()
            {
                var reader = new XmlTextReader(xmlAddress);
                var feed = SyndicationFeed.Load(reader);
                enumerator = feed.Items.GetEnumerator();
            }

            public bool Read()
            {
                return enumerator.MoveNext();
            }

            public string GetTitle()
            {
                return enumerator.Current.Title.Text;
            }

            public string GetDescription()
            {
                string text = Regex.Replace(enumerator.Current.Summary.Text,
                                             "<(.|n)*?>", String.Empty);
                return text;
            }       
        }
    }

    1. Set the Deployment Target at the project to Client: Yes and deploy

    Populate the RssContentTable

    1. Create a find method on the RssFeedTable
    2. Copy this code and substitute the parameter in the find method with one of yours

    static void populateFeedTable(Args _args)
    {
        System.Exception ex;
        RssFeedTable feedTable = RssFeedTable::find("techat");
        RssFeedContent content; 
        ErpCoder.RssFeed.Reader reader;
        InteropPermission permission;
     
        permission = new InteropPermission(InteropKind::ClrInterop);    
        permission.assert();

        try
        {
            reader = new ErpCoder.RssFeed.Reader(feedTable.Uri);
            reader.Load();

            while(reader.Read())
            {
                content.clear();
                content.Title = reader.GetTitle();
                content.Text = reader.GetDescription();
                content.FeedId = feedTable.FeedId;
                content.insert();
            }
        }
        catch(Exception::CLRError)
        {
            ex = CLRInterop::getLastException();
            error(ex.get_Message());
        }

        CodeAccessPermission::revertAssert();
    }

    Create a job to test the fulltext index

    1. Create a new job and copy this code

      static void queryFullText(Args _args)
      {
          RssFeedContent feedContent;
          Query query = new Query();

          QueryBuildDataSource qbdsContent =
           query.addDataSource(tableNum(RssFeedContent));

          QueryBuildRange rangeText =
           qbdsContent.addRange(fieldNum(RssFeedContent,Text),
                                1,QueryRangeType::FullText);
          QueryRun queryRun;
          rangeText.value("Office Hyper-V");

          queryRun = new QueryRun(query);
          while(queryRun.next())
          {
              feedContent = queryRun.get(tableNum(RssFeedContent));
              info(feedContent.Text);
          }
      }

    2. Subsitute the value of the fulltext range value with yours
    3. Test the query

    image

    Using a Seagate Momentus XT Hybrid HDD to boost performance on a Dynamics AX 2012 presentation laptop

    Momentus XT is a hybrid HDD that combines a 7200rpm drive with a large SSD cache. I’ve bought one to run a  Dynamics AX 2012 presentation laptop. By design the performance is getting better for frequent tasks. Here are my results:

    Testcases:

    1. Boot Windows Server 2008 R2 until STRG+ALT+DEL screen appears
    2. Start Dynamics AX client and wait until role center has finished loading and rendering reports
    3. Post a sales order confirmation with 20 lines

    Laptop: HP 8540w Mobile Workstation, 8GB RAM, Core i7 2,8GHz
    Software: Windows Server 2008 R2 SP1, Dynamics AX 2012 CU1, SQL Server 2008 R2, Enterprise Portal with SharePoint Server 2010

      HDD XT #1 XT #2 XT #3 XT #4 XT #5
    Boot 03:05 03:13 02:36 01:48 01:54 01:46
    Start AX 00:51 00:40 00:31 00:18 00:17 00:18
    Confirmation 02:30 01:40 00:59 00:59 01:07 00:59

    @Dynamics AX Technical Conference

    You can find me at the Dynamics AX Technical Conference in Nice

    Extend SalesTable2Line Framework

    Dynamics AX provides a Framework for updating changes made on SalesTable fields to SalesLine fields. The update method can be configured within Dynamics AX at Accounts Receivable > Setup > Parameters > Updates > “Update order Line”. This form is used to configure if and how changes made to the SalesTable are written to the lines. This framework can be extended to update your own fields, like a “Notes” field in the example below.

    Dynamics AX 2009 Update Order Lines

    1. Create a new field called "SalesNotes” in the SalesTable and SalesLine
    2. Add the SalesTable.SalesNotes field to the Field Group HeaderToLineUpdate at the SalesTable
      Put Sales Notes field HeaderToLineUpdate group in the SalesTable
    3. Display the new fields in the SalesTable form e.g. in the General tab
    4. Open the SalesTable2LineParameters table in the table browser and remove all records. Don’t worry, these data will be populated automatically and is the basis for the “Update order line” form.
    5. Add the following line to the SalesTable2LineField.lineUpdateDescription method

      case fieldnum(SalesTable, SalesNote):
          return fieldid2pname(tableNum(SalesLine), fieldNum(SalesLine, SalesNote));

      Modify the SalesTable2LineField.lineUpdateDescription method

       

    6. Add a parameter method for the SalesNote field to the AxSalesTable class

      public SalesNote parmSalesNote(SalesNote _salesNote = ”)
      {
          if (!prmisdefault(_salesNote))
          {
              this.setField(fieldnum(SalesTable, SalesNote), _salesNote);
          }

          return salesTable.SalesNote;
      }

    7. Add a parameter method for the salesNote field to the AxSalesLine class

      public SalesNote parmSalesNote(SalesNote _salesNote = ”)
      {
          if (!prmisdefault(_salesNote))
          {
              this.setField(fieldnum(SalesLine, SalesNote), _salesNote);
          }

          return salesLine.SalesNote;
      }

    8. Create a setSalesNote method on the AxSalesLine class

      protected void setSalesNote()
      {
          if (this.isMethodExecuted(funcname(), fieldnum(SalesLine, SalesNote)))
          {
              return;
          }

          this.setAxSalesTableFields();

          if (this.isAxSalesTableFieldsSet() || this.axSalesTable().isFieldModified(fieldnum(SalesTable, SalesNote)))
          {
              this.parmSalesNote(this.axSalesTable().parmSalesNote());
          }
      }

    9. Modify the setTableFields method to call the setSalesNote method
      Call the setSalesNote method
      Test your modification. Open the “Update order line” form and set the update method for Sales Notes to “Prompt”. Open the sales order details form, go to your new field, modify the text and save. A dialog will appear and ask your to update the Note fields. Click OK, and review the Sales Notes in the SalesLines.

    Modify the SalesNote value in a sales order

    Review the update on the sales line

    Evolution: Lenovo x100e to Lenovo x121e

    I’ve recently purchased a Lenovo x121e with AMD Processor to replace my good old x100e Laptop. In general I’d prefer HP but there are some reasons why I’ve become a fan of Lenovos x100* series.

    • Thinkpad like style, keyboard and quality
    • Excellent driver support
    • Fair price, x121e with AMD processor ~ 370 €
      I’ve decided to buy the AMD version because the dual core CPU and 4 GB RAM are sufficient for working with Office and running Skype. Its much cheaper than the Intel i3 version. The design has been improved, it’s a bit larger than the x100e and got an HDMI port.

    x110ex121e

    However, the x121e AMD version does not have an integrated WWAN module. This may be one reason why its that cheaper compared to the Intel version. Fortunately the old x100e has one (Gobi 2000) that can be transferred to the x121e.

    1. Open the back of both laptops, the Qualcomm Gobi 2000 module is located on the lower left corner
      x100e_3G_module
    2. Remove the module from the x100e laptop
      Qualcom Gobi 2000
    3.   Put it in the free x121e slot, fix it and connect both cables
      gobi2000_in_x121e
    4. Close the back of the x121e and boot windows. Download the latest Qualcomm Gobi 2000 driver software from Lenovo. Search for x100e drivers, and use the ThinkPad Activation tool for the x121e.
      access3AT 

    Add Sound to Infolog

    I’ve been asked by a colleague if it is possible to let the Infolog make a noise depending on the log type, e.g. a *beep* for an info, a *pling* for a warning and an evil noise for an error. Fortunately we can use .NET in AX 2009. The System.Media.SystemSound class already provides access to the typical system sounds. I’ve modified the Info class in AX this way:

    Exception add(
        Exception _exception,
        str _txt,
        str _helpUrl = ”,
        SysInfoAction _sysInfoAction = null,
        boolean buildprefix = true)
    {

        int numOfLines,i;
        int actionClassId;
        container packedAction;
        xSession session;   

        System.Media.SystemSound sound;
        InteropPermission permission;

        ;

    // default infolog code here …

        permission = new InteropPermission(Interopkind::ClrInterop);
        permission.assert();
       
    switch(_exception)
        {
            case(Exception::Info):
            sound = System.Media.SystemSounds::get_Asterisk();
            break;
            case(Exception::Warning):
            sound = System.Media.SystemSounds::get_Hand();
            break;
            case(Exception::Error):
            sound = System.Media.SystemSounds::get_Exclamation();
            break;
        }    
        if(sound!=null)
            sound.Play();

        CodeAccessPermission::revertAssert();

        return super(_exception, (buildprefix?getprefix():”)+_txt);
    }

    MB6-820 Dynamics AX 2009 Installation & Configuration

    I’ve passed the MB6-820 Dynamics Ax 2009 Installation & Configuration exam. Questions are fair and with some experience installing AX in different environments you have a good chance to pass the exam with a high score.

    Dynamics Certifications

    image

    Windows and SQL Server Certifications

    image

    HP MT 3300 in SBS 2008 Environment running Dynamics AX 2009

    image

    I’ve recently added a HP MT 3300 Desktop PC to a Small Business Server 2008 domain running Dynamics AX 2009. Out of the box I was facing two issues:

    1) SBS 2008 reported an error it could not communicate with the new client machine.

    2) Opening the AOT was freezing the Dynamics AX client and crashed after a while because of insufficient memory. Very strange issue that could not to be fixed with any rollup or hotfix for Dynamics AX 2009.

     

     

    Solution 1)
    Per default the machine is running Norton Internet Security. Go to Settings > Network Settings > Firewall > Access Control. Set the SBS Server machine to Full Trust.

    image

    Solution 2)
    Thanks to Microsoft Support: HP Security Manager is causing this issue (not only on MT 3300). Go to C:\Program Files (x86)\Hewlett-Packard\HP ProtectTools Security Manager\Bin and find the DpFbView.dll file. Rename the file to DpFbView.old.

    Enterprise Portal Custom Filter Error after a short time

    Again I experienced a strange behavior within Dynamics AX 2009 Enterprise Portal. I’ve created a AxGridView using an AxDataSource connected to a DataSet in Dynamics AX. The DataSet holds a setFilter method to set values on some QueryBuildRanges. Moreover I’ve create a button in my AxUserControl Webpart that invokes the setFilter method with some values.

    protected void SearchButton_Click(object sender, EventArgs e)
    {
       string value1 = TextBox1.Text;
       string value2 = TextBox2.Text;
       AxDataSourceMyTable.GetDataSet().DataSetRun.AxaptaObjectAdapter.Call  
        (“setFilter”,value1,value2);
    }

    public void setFilter(str _value1, str value2)
    {;
       qbrSomeField.value(_value1);
       qbrAnotherField.value(_value2);
       MyTable_DS.executeQuery();
    }

    This implementation worked fine the first time using the webpart. However, after a very short time I got an error telling me that no Business Connector Session was found.

    Microsoft.Dynamics.Framework.BusinessConnector.Session.Exceptions.NoKernelSessionException

    First I thought of some kind of timeout and played with IIS settings. But Google found this discussion where it is explained that Dynamics AX deletes the QueryBuildRange objects after a very short time, and therefore the call fails. The solution is to use SysQuery::findOrCreateRange .

    public void setFilter(str _value1, str value2)
    {
       QueryBuildDataSource qbds;
       ; 
       qbds = MyTable_DS.query().dataSourceTable(tableNum(MyTable))
       SysQuery::findOrCreateRange(qbds,fieldNum(MyTable,Field1)).value(_value1);
       SysQuery::findOrCreateRange(qbds,fieldNum(MyTable,Field2)).value(_value2);
       MyTable_DS.executeQuery();
    }

    Follow

    Get every new post delivered to your Inbox.