Tuesday, October 26, 2010

Ax2009 Reporting services installation Error out on iis

On the Box:
Server: windows 2008 server R2.
SQL 2008.

When installing Reporting Extensions for Ax 2009,the pre-requisite page shows that IIS is not installed even thou you may have installed it. In the log file,you will find that the installation fails at IIS.

For the workaround, install the following IIS components from Manage Your server-> Server Roles->role services.

Install the selected components and You wont be asked to install IIS pre-requisite.


Thursday, October 21, 2010

SQL Database Error in Ax2009

When I try to execute a query which uses complex joins in dynamics ax 2009, the sql buffer size is reached depending upon the buffer size of configuration database size. Here is the error in the infolog.
Error:
The total, internal size of the records in your joined SELECT statement is 25666 bytes, but Microsoft Dynamics is by default performance-tuned not to exceed 24576 bytes.
It is strongly recommended that you split your table(s) into smaller units.
Alternatively, you have to specify a 'Buffer size' value of 26 Kbytes or higher in the 'SQL' tab page in the Microsoft Dynamics Configuration Utility. The default value is 24 Kbytes.


 As a solution, you can increase the buffer size in the ax server configuration manager by multiples of 2. By default it has 24kb of buffer.Also note how the page memory use increases from task manager of 'AX32' services.The increase in buffer id proportional to the increase in PF memory.

Thursday, October 14, 2010

Copying Infolog -Sending EMail from ax2009

This is a small post to send and configure mail in ax 2009.I have had a requirement to copy the infolog at the end of some function and send it to the user. This is a code snippet (not the actual one though) how I managed.
First you need to set a template for the mail (Basic-> set up->Email Template). I have created a template as shown.


%name% and %matter% are dynamic macro taken from runtime.You can have your code to take up customer name and description from a failed sales order for an instance.
A job is written, which produces three info message logs and sent it to the email.The template is helpful in forming email body parameters. You can send the mail from the email address of customer.

static void SendEmail(Args _args)
{
    SysInetMail mail;
    Map mappings;
    COM document;
    COM body;
    str ret, subject, matter;
    sysemailid emailid;
    languageId languageId;
    SysEmailMessageTable message;
    Xinfo info;
    int infoLogCounter;
    Log log;
    int i=1;
    container con;


    SysInfologEnumerator enum ;


    #help
    ;
    info( " hello world");
    error('this is error');
    error('this is  error 2 ');
    //info - if you want to copy these info msg to a email in some functionality
     log = Info::infoCon2Str( infolog.copy(1,infolog.num()));
     con = infolog.copy(1,infolog.num());
     enum = SysInfologEnumerator::newData(con );
      while (enum.moveNext())
    {
        matter +=strfmt('
%1 -> %2 ',int2str(enum.currentException()), enum.currentMessage());
    }


    emailId = 'Log';
    languageId = 'en-us';
    mail = new SysInetMail();
    mail.parmForceSendDialog(true); // this will show u a dialog before sending.
    mappings = new Map(Types::String, Types::String);
    mappings.insert('name', 'parthav');
    mappings.insert('matter',matter );
    message = SysEmailMessageTable::find( emailId,languageId);
    ret = SysEmailMessage::stringExpand(message.Mail, mappings);
    ret = WebLet::weblets2Html4Help(ret, '');
    document = new COM(#HTMLDocumentClassName);
    SysEmailTable::insertHTML2Document(document, ret);
    body = document.body();
    subject = SysEmailMessageTable::find(emailId, languageId).Subject;
    mail.sendMail( 'parthav.patel@ignify.com'   ,  'CSV Import Log',    body.OuterText() ,false);
    
}
After hitting f5,you will get a dialog and composition of email. You can avoid this by setting mail.parmForceSendDialog(false) in the above code.


You are now ready to send the mail of your report.


How to find backend field name in ax2009

If you want to use DB field name sometimes to import data like dimensions, you might want to consider getting DB field names. Here is the script which does that.
static void BackendFieldName(Args _args)
{
    sysdictfield df;
    ;

    df = new sysdictfield( tablenum(CustTable),fieldNum(CustTable, Dimension),2);

    info(strfmt("%1",df.name(DbBackend::Native,2)));
}

Problem with HotFix RollUp 5 (982811)

Ax 2009 Hotfix RollUp 5 is one potential problem when applied to a box having multiple AOS or Applications. When It is applied to one AOS/Application and not to others, the client is obviously upgraded. The problem now when the client is on RU 5 and the Application Kernel build is lower than RU5 is that you see only one row of data. Only one record is displayed for any form although when you filter you find the desired data.

This problem can be avoided when the kernel application build is upgraded to RU5.

EP Error on installation

When I tried to install EP on Farm Non-Admin server I got the following error. I tried it from the admin account of ax.
EP Installation Error
On Event Viewer:
The trust relationship between this workstation and the primary domain failed.

Work around:
1.Check the .net Business connector configuration settings. This might be a naive approach and considering one must have already looked up seeing the log, I am suggesting to do the following work arounds.
1)      Stop firewall, all its services, delete all unused inbound  policies on firewall.
2)      Install AOS , debugger and .net connector upto RU3 on the work station. I don’t know why it required AOS but failed without it.May be its with the configuration.
3)      .Delete the workstation from domain and add it again – DNS issue.This is a WSS issue.
4)      .If database was restored & EP is installed on one server – clear the BC Proxy account from form.
5)      Recompile sysDevelopmentProxy class – ensure it compiles without error for .Net connector to work successfully.
6)      Check the site bindings from Share Point servers, also from this server.
Install EP & Role center with some luck.


Workflow in Ax 2009 Troubleshooting


The request failed with HTTP status 405: Method Not Allowed.


I had an error when trying to validate his workflow url with the following message being displayed: “The request failed with HTTP status 405: Method Not Allowed.” He was running on the following System configuration:
1. Windows 2008 R2 64 bit.
2. SQL Server 2008
3. IIS 7
To resolve this error. I believe the simple solution  is to set your IIS application Pool’s 32bit property to true
IIS –>Application pool of WF–> rightclick advanced settings and change 32 bit to TRUE.

Wednesday, July 21, 2010

Importing data in Ax 2009 with validations

I have created a solution in Ax 2009 to migrate bulk data from a csv format. It is better than the standard excel tool as no code for validation needs to be written. You have two options to validate the data of a field from its master table and one from relation. 
Another striking feature is that the field in the file can be arranged randomly with the AX field Name.It gives you independence to arrange the fields in any order in the file using the AX field names on the header. Also, there is a facility to extract a template and data, which appends a “$” to all mandatory fields. It can be imported as it is.


When using a bulk upload, it is sometimes difficult to analyze the info log as its limit is 10k lines. Here you have an error file and log file setting which stores the invalidated data. The error file has those records from the actual file that were not Inserted/Updated/Validated.


The Options available are:
Read - Import Mode
Write - Export Mode (to file)
File path options.
Import Mode - Validate only with out import ( no import takes place) , Insert new only, Insert new and update existing.
Entity - The csv import tool has many predefined scripts to take care of customer, vendor , address,employees, item master and COA. You just need to put the data in the particular format like in the item master the data has to be right skewed and the last three fields must be Prices.
The address import has a common field setting for customer, vendor and employees.
The csv import options form

Validation Type
 1) Validate Relation on Table
 If you want to validate the data based on the parent table having field relation on Enum, then Validate relation on EDT is used.
2)  Validate Relation on EDT
 If you want to validate the data based on the Table relations then  Validate relation on Table is used. This mode is not preferred while updating.The ref fields also get validated, so you need to ignore that error.
On selecting Generic entity, you get options to select the table.  

Using Validation with an example:
Let us consider we have 3 records of customer to be migrated in a csv file.The payment Term has not come correct to the file(i.e. the data does not exist on paymterm table).
Customer 3 records. Red - error while  validation






Notice that the field names are the AX field names. They can be arranged in any order in the file. When the Validate Relations on Table option is chosen, the last two records will not be inserted because payment term Id 'wrond data' does not exist on the PaymTerm table.You will get an info log like:
The error log and the error records can also be found at the path mentioned in the error log parameters.You can change the data that is not imported from the error file of records and re import. The error file contains all the records that are not inserted due to some error.This is very useful as the wrong data is filtered effectively. The log file will copy the info log with the reference line number as shown below.

Code used to build dynamic query for validating EDT -


 for (relationLine=1; relationLine <= linesCnt; relationLine++)
        {
            fieldId = dictRelation.lineExternTableValue(relationLine);
            switch( dictRelation.lineType(relationLine) )
            {
                case TableRelation::Dataset :
                case TableRelation::Field :
                     _queryBuildRange1 = _queryBuildDataSource.addRange(fieldId);
                     _queryBuildRange1.value( _Value );
                     break;


                case TableRelation::ExternFixed :
                     _queryBuildRange2 = _queryBuildDataSource.addRange(dictRelation.lineExternTableValue(relationLine));


                     if( _array>0)
                        _queryBuildRange2.value(int2str(_array));
                     else
                        _queryBuildRange2.value(int2str(dictRelation.lineTableValue(relationLine)));
                     break;
             }


        }


Validate Table Realtion-


 switch( dictRelation.lineType(relationLine) )
                    {
                        case TableRelation::Field :
                              thisFieldId = dictRelation.lineTableValue(relationLine);
                              printFieldId = thisFieldId;
                              if( (_commonRecord.(thisFieldId)) && ValidationRequired && thisFixedValidation )
                              {
                                    _queryBuildDataSource.addRange(ExtfieldId).value( _commonRecord.(thisFieldId) );
                              }
                              else
                              {
                                    ValidationRequired = False;
                              }
                             break;
                        case TableRelation::ThisFixed :
                            thisFieldId = dictRelation.lineTableValue(relationLine);
                            if( _commonRecord.(thisFieldId) && (_commonRecord.(thisFieldId)!= ExtfieldId && ValidationRequired ))
                            {
                                thisFixedValidation = False;
                            }
                            break;
                        case TableRelation::ExternFixed :
                             if( ValidationRequired)
                             _queryBuildDataSource.addRange(dictRelation.lineExternTableValue(relationLine)).value(int2str(dictRelation.lineTableValue(relationLine)));
                             break;