Friday, 12 December 2014

Debugger not installed

I was writing some automation scripts and as part of the automation I was supposed to specify AX client log folder path in the cleanup task but by mistake I gave client bin folder path. This resulted in everything being wiped from that folder and clicking on the AX client shortcut gave an error. I was able to recover from this by running the repair on the AX client in "Control Panel\Program and Features".

All was fine until I hit a breakpoint and a message popped up saying "debugger is not installed. Please install the debugger". But I had the debugger installed. The repair on the client fixed the client related files but not the debugger. So I ran the installer again and there the debugger option was already ticked so the installer did not let me proceed.

The solution was simple. Just copy the AXdebug.exe from the following location in the installer folder to the client bin folder and everything this was fine (for 64-bit machine).

..\Msi\Components64\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin

This posting is provided "AS IS" with no warranties. Use code at your own risk.

Monday, 10 November 2014

DynamicsPerf capture stat job failing

Recently I installed DynamicsPerf 1.20 on our production servers. After that I noticed that capture stat job was failing. A detailed look at the error log showed that it was failing at the step where it populates 'SQL Virtual Log File Information' and although the stored procedure does have try/catch block to handle exceptions it was still not executing the rest of steps.

It turned out that one of our SQL stored procedure was setting 'show advanced options' to 1 and after doing its business it was setting it back to 0. As a result when the capture stat job was trying to enable 'Ad Hoc Distributed Queries' it was getting an error.

I had to modify the capture stat stored procedure to check for 'show advanced options' and set it to 1 if not already set and at the end set it back to original value.

This posting is provided "AS IS" with no warranties. Use code at your own risk.

Friday, 7 March 2014

Query SSAS from X++ using DMX

For one of our projects we needed to query data from SQL Server Analysis Service (SSAS). We choose DMX (Data Mining Extensions) to do that. Following code shows how to do it

static void QuerySSASUsingDMX(Args _args)
{
    str                                dmxConnectionString, dmxQuery, value;
    int                                i, rowCount;
    
    System.Data.DataTable              dataTable;
    System.Data.DataRowCollection      collection;
    System.Data.DataRow                row; 
    System.Object                      object;
    
    Microsoft.AnalysisServices.AdomdClient.AdomdConnection      adomdConn;
    Microsoft.AnalysisServices.AdomdClient.AdomdDataAdapter     adomdDataAdapter;
    
    dmxConnectionString = 'Data Source=SSAS_SERVER;Catalog=CafeAssociation';
    dmxQuery = 'Select flattened predictAssociation ([CafeAssociation].[v Cafe Assoc Seq Line Items], INCLUDE_STATISTICS, 20) from [CafeAssociation]';
    
    dataTable = new System.Data.DataTable();
    
    adomdConn = new Microsoft.AnalysisServices.AdomdClient.AdomdConnection(dmxConnectionString);
    adomdDataAdapter = new Microsoft.AnalysisServices.AdomdClient.AdomdDataAdapter(dmxQuery, adomdConn);
    adomdDataAdapter.Fill(dataTable);
    
    collection = dataTable.get_Rows(); 
    rowCount = collection.get_Count();    
    
    for (i = 0; i < rowCount; i++) 
    { 
        row = collection.get_Item(i); 
        object = row.get_Item(0);
        value = object.ToString();
        
        info(strFmt('%1. %2', i+1, value));
    } 
    
    adomdConn.Close();
}

Microsoft.AnalysisServices.AdomdClient is not available in Dynamics AX and can be manually added to the "References" node in AOT.

This posting is provided "AS IS" with no warranties. Use code at your own risk.

Friday, 24 January 2014

SSRS service start issue

Last week I configured multiple instances of SQL Server Reporting Service on the same computer for AX2012. I did so following the article on TechNet. One of the step is to Modify Reporting Services configuration files. After completion of this step I tried re-starting the SSRS service and it won't start. Windows event log had following error.
Service cannot be started. System.Exception: Default appdomain failed to initialize.
   at Microsoft.ReportingServices.Library.ServiceAppDomainController.Start()
   at Microsoft.ReportingServices.Library.ReportService.OnStart(String[] args)
   at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)
SSRS's own log which can be found in the folder "C:\Program Files\Microsoft SQL Server\MSRS10_50.<INSTANCE_NAME>\Reporting Services\LogFiles" had the following text in the log file.
rshost!rshost!540!01/20/2014-14:40:35:: i INFO: CLR runtime is initialized.
rshost!rshost!540!01/20/2014-14:40:35:: i INFO: Derived memory configuration based on physical memory as 4193848 KB
appdomainmanager!DefaultDomain!328!01/20/2014-14:40:35:: i INFO: Entered managed ServiceMain in DefaultDomain.
configmanager!DefaultDomain!ad8!01/20/2014-14:40:36:: e ERROR: Error loading configuration file: The configuration file contains an element that is not valid. The #text element is not a configuration file element.
library!DefaultDomain!ad8!01/20/2014-14:40:36:: e ERROR: Throwing Microsoft.ReportingServices.Diagnostics.Utilities.ServerConfigurationErrorException: , Microsoft.ReportingServices.Diagnostics.Utilities.ServerConfigurationErrorException: The report server has encountered a configuration error.  ---> System.Exception: The configuration file contains an element that is not valid. The #text element is not a configuration file element.
   at Microsoft.ReportingServices.Diagnostics.ExtensionsConfiguration.ParseExtensionElement(XmlNode child, Extension& extension, String childName)
   at Microsoft.ReportingServices.Diagnostics.ExtensionsConfiguration.ParseDataExtensions(XmlNode child, ExtensionArray array)
   at Microsoft.ReportingServices.Diagnostics.ExtensionsConfiguration.ParseExtensions(XmlNode child, ExtensionArray array)
   at Microsoft.ReportingServices.Diagnostics.ExtensionsConfiguration.ParseXML(XmlNode node)
   at Microsoft.ReportingServices.Diagnostics.RSConfigurationFileManager.ParseDocument(XmlDocument xmlConfiguration)
   at Microsoft.ReportingServices.Diagnostics.RSConfigurationFileManager.LoadDocument()
   at Microsoft.ReportingServices.Diagnostics.RSConfigurationFileManager.LoadConfiguration()
   --- End of inner exception stack trace ---;
appdomainmanager!DefaultDomain!ad8!01/20/2014-14:40:36:: e ERROR: Appdomain:1 DefaultDomain failed to initialize. Error: Microsoft.ReportingServices.Diagnostics.Utilities.ServerConfigurationErrorException: The report server has encountered a configuration error.  ---> System.Exception: The configuration file contains an element that is not valid. The #text element is not a configuration file element..
appdomainmanager!DefaultDomain!710!01/20/2014-14:40:36:: e ERROR: Windows service failed to start. Exception: System.Exception: Default appdomain failed to initialize.
   at Microsoft.ReportingServices.Library.ServiceAppDomainController.Start()
   at Microsoft.ReportingServices.Library.ReportService.OnStart(String[] args)
servicecontroller!DefaultDomain!540!01/20/2014-14:40:36:: i INFO: RPC Server stopped. 
servicecontroller!DefaultDomain!540!01/20/2014-14:40:36:: i INFO: Service shutting down.
A quick search on internet resulted in different proposals some involving security rights issue other suggesting a reinstall. As the error suggests there is something wrong with the configuration file.

The clue came from SQL Server Support Team blog. It turned out that while making the changes to the configuration file rsreportserver.config I left some extra text. Comparing the corrupted file with a healthy file, using a text editor compare tool, highlighted the changes I made and the extra stuff entered by mistake. I removed the extra stuff and the service started successfully.

This posting is provided "AS IS" with no warranties. Use code at your own risk.

Sunday, 22 December 2013

Get distance between two points using Google API

The following code uses Google API to get distance between two latitude/longitudes.

 static void getGoogleDistance(Args _args)  
 {  
   System.Net.HttpWebRequest  request = null;  
   System.Net.HttpWebResponse response = null;  
   System.IO.Stream      stream = null;  
   System.IO.StreamReader   streamReader = null;  
     
   LogisticsAddressLatitude  fromLatitude, toLatitude;  
   LogisticsAddressLongitude  fromLongitude, toLongitude;  
   
   CLRObject          clro = null;  
   
   real            distance;  
   str             baseUrl, url, xml, disStr;  
   
   XmlDocument         xmlDoc;  
   XmlNodeList         xmlNodes;  
   XmlNode           xmlNode;  
   
   baseUrl = "http://maps.googleapis.com/maps/api/distancematrix/xml?origins=%1,%2&destinations=%3,%4&mode=Car&language=gb-en&sensor=false&units=imperial";  
   new InteropPermission(InteropKind::ClrInterop).assert();  
     
   // London  
   fromLatitude = 51.5072;  
   fromLongitude = -0.1275;  
     
   // Manchester  
   toLatitude = 53.4667;  
   toLongitude = -2.2333;  
   
   try  
   {  
     distance = 0;  
   
     url = strFmt(baseUrl, fromLatitude, fromLongitude, toLatitude, toLongitude);  
   
     clro = System.Net.WebRequest::Create(url);  
     request = clro;  
     response = request.GetResponse();  
   
     stream = response.GetResponseStream();  
     streamReader = new System.IO.StreamReader(stream);  
     xml = streamReader.ReadToEnd();  
   
     xmlDoc = XmlDocument::newXml(xml);  
     xmlNodes = xmlDoc.selectNodes('//DistanceMatrixResponse//row//element//distance//text');  
     xmlNode = xmlNodes.nextNode();  
     disStr = strRem(xmlNode.innerText(), ' mi');  
   
     if(disStr != '')  
     {  
       distance = str2num(disStr);  
     }  
   }  
   catch  
   {  
     Global::exceptionTextFallThrough();  
   }  
   CodeAccessPermission::revertAssert();  
   
   info(strFmt('Distance: %1', distance));  
 }  

This posting is provided "AS IS" with no warranties. Use code at your own risk.