CIL (Common Intermediate Language)

  1. Introduction (what Is CIL?)

CIL, formally known as MSIL (Microsoft Intermediate Language)

CIL, stands for Common Intermediate Language and it works together with the CLI or Common Language Infrastructures, which is basically a set of rules on programming languages that will compile with the CIL.

This is the way of convert source code to byte code. These steps divided into three level.

  1. Compilation (source code)
  2. CIL (P-code)
  3. CLR (Byte code)

capture

2.Types of  CIL

 

There are two types of CIL, Incremental CIL & Full CIL

  • Incremental CIL:

Increment CIL would compile only the objects that were modified since the last incremental compilation.

Incremental CIL generation involves only the “changed” p-code artifacts that need to be converted into target CIL.

 

  • Full CIL:

Full compile would compile wholes objects. Convert p-code into CIL referred as byte code at run time. Full CIL generation is mandatory when we do modify anything on the XppIL folder.

3.Why CIL?

The CLR can execute code faster than the AX-Kernel version in the following cases.

  1. Computationally intensive code that does not a lot of data access.
  2. Memory intensive code(objects stored in memory)

4.Limitations of CIL   

  • CIL session does not have access to all the system classes.
  • Only classes, tables, base enum are eligible for CIL .queries and forms are not applicable for CIL.
  • Runbuff () and evalbuff () method code are not coming in CIL.
  • This is always server side code.

 

 

5.Some basic error related to CIL

  1. Metadata exception
  2. The CIL Generator found errors and could not save the new assembly:
  3. The given key was not present in the dictionary.
  4. Source array was not long enough.
  5. A parameter could not be serialized.

Solution:

  1. metadata contains data of other data like author ,data created and data modified some time these data were missing or not updated

Then this error comes. This is solved by full CIL

  1. This is because assembly issue just follow these steps.

Stop AOS

Delete xppil files except folders

Start AOS

Do full compile

Do CIL

  1. Restart the server.

If error still coming then cleared cashes and delete AUC files

Error still coming cleared xppil files.

  1. Same xppil clear process if errors are still there and you have no error when compile X++, just comment the code notice in Compiler output with /*..*/, recompile CIL and delete comment tag

 

  1. For a quick resolve: uncheck option “Execute business operations in CIL” under Tools-> Options -> Development tab.

The reason is that you haven’t been able to do a successful FULL CIL compile, Run again and try to fix the error in CIL.

 

  1. Correct order for CIL   

       Compile, CIL (Incremental & Full CIL), Synchronize or Compile, Synchronize, CIL (Incremental & Full CIL)

        CIL generation and DB synchronization are not related at all, therefore their order doesn’t matter.

CIL must be run after X++ compilation, because it depends on information provided by X++ compiler.

  1. What is xppIL folder?

XppIL Folder contains source code (.xpp extension) metadata & compiled code.

Source code are used to debug CIL code in Visual Studio when working with services and batches. In xppIL folder there are some bunch of       files. These files are Net Module type files and they only contain type metadata and compiled code. The compilation creates an assembly (dynamic.ax.application.dll) on the other hand Net Module contains .net assemblies ( dynamic.ax.application.dll.netmodule)

Path for find xppIL folder:  C:\Program Files\Microsoft Dynamics AX\60\Server\Server name \bin\XppIL

  1. How to CIL by x++

We can run x++ code as CIL by using this method:

                Global::runclassmethod dll

Advertisements

Split domain from current user Id(SSRS)

Some time in ssrs report designing we need to display only user id but by default user id display with domain name like “domain\userid”. when we have to show only the user id then follow these expression .

1.   =Split(User!UserID, “\”).GetValue(1)

2.  = Right(User!UserID, Len(User!UserID) – InStr(User!UserID, “\” ))

3. =mid(User!UserID , InStr(User!UserID,”\”)+1)

select any 1 option .

Create Payment Journal

static void nidhipaymentjournal(Args _args)
{
Ledgerjournalname       ledgerjournalname;
LedgerjournalTable      LedgerjournalTable;
LedgerjournalTrans      LedgerjournalTrans;
LedgerjournalCheckPost  LedgerjournalCheckPost;
NumberSeq               numberSeq;
Container               con;
Filename                filename, Filename2;
FileIOPermission        permission;
TextIO                  textIO, textIO1;
Dialog                  dialog;
DialogField             dialogField;
AccountNum              customerAccount=”INMF-000001″; // ‘BRMF-000001’;
AccountNum              offsetAccNum = “IND OPER”;
bankAccountTable        bankAccountTable;
DimensionDynamicAccount offsetLedgerDim;
DimensionAttributeValueCombination  ledgerDimension;

#File

select ledgerjournalname where ledgerjournalname.JournalName ==  “CUSTP”; //”Test”;
ttsBegin;
LedgerjournalTable.JournalName = ledgerjournalname.JournalName;
LedgerjournalTable.initFromLedgerJournalName();
LedgerjournalTable.JournalNum  = JournalTableData::newTable(LedgerjournalTable).nextJournalId();
// LedgerjournalTable.OffsetAccountType =  LedgerJournalACType::Ledger;
// LedgerjournalTable.OffsetLedgerDimension = 110110;

LedgerjournalTable.insert();
ttsCommit;

ttsBegin;
numberSeq                               =   NumberSeq::newGetVoucherFromId((ledgerjournalname.NumberSequenceTable));
LedgerjournalTrans.Voucher              =   numberSeq.voucher();
LedgerjournalTrans.JournalNum           =   LedgerjournalTable.JournalNum;
LedgerjournalTrans.CurrencyCode         =   “INR”;
// added…..loffset ledger dimension..
// offsetLedgerDim                        = DimensionStorage::getDynamicAccount(‘IND OPER’,LedgerJournalACType::Bank);
//……….
LedgerjournalTrans.ExchRate             =   Currency::exchRate(LedgerjournalTrans.CurrencyCode);
// LedgerjournalTrans.LedgerDimension      =   DimensionStorage::getDynamicAccount(‘INMF-000001’,LedgerJournalACType::Cust);

LedgerjournalTrans.AccountType          =   LedgerJournalACType::Cust;
LedgerjournalTrans.parmAccount(customerAccount,LedgerjournalTrans.AccountType);
LedgerjournalTrans.Txt                  =   ‘Testing’;//conPeek(con,1);
LedgerjournalTrans.AmountCurCredit      =    10;//conPeek(con,3);
LedgerjournalTrans.TransDate            =   systemDateGet();//str2Date(conPeek(con,4),123);
LedgerjournalTrans.OffsetAccountType    =   LedgerJournalACType::Bank;//LedgerjournalTable.OffsetAccountType;
//LedgerJournalTrans.offsetacco
//for bank  offset account
switch( LedgerjournalTrans.OffsetAccountType)
{
case    LedgerJournalACType::Bank   :   select firstOnly bankAccountTable
join RecId from ledgerDimension
where ledgerDimension.DisplayValue      == bankAccountTable.AccountID
&&    bankAccountTable.AccountID        == “IND OPER”;
//  trans.parmOffsetLedgerDimension(ledgerDimension.RecId);

LedgerjournalTrans.OffsetLedgerDimension = ledgerDimension.RecId ;

}
//end………………………
LedgerjournalTrans.DefaultDimension      = CustTable::find(customerAccount).DefaultDimension;
LedgerjournalTrans.OffsetDefaultDimension=  CustTable::find(customerAccount).DefaultDimension;
LedgerjournalTrans.insert();
ttsCommit;

// for posting ……………………………….
LedgerjournalCheckPost = LedgerjournalCheckPost::newLedgerJournalTable(LedgerjournalTable, NoYes::Yes);
LedgerjournalCheckPost.run();
//end…………………………………..

info(strFmt(“%1”,LedgerjournalTable.JournalNum));
}

How to add filters on Form

Step 1

Declare a class variable
In the ClassDeclaration method of form declare a QueryBuildRange

class FormRun extends ObjectRun
{
QueryBuildRange      abcQueryRange;
ABC                  abcCode;
}

Step 2
Initialize this range in the init method of datasource after super() call.

public void init()
{
super();
abcQueryRange = this.query().dataSourceName(‘X’).addRange(fieldnum(X, ABC));

}

Step 3

Now assign the filter value in the executeQuery method of same datasource before super() call.

public void executeQuery()
{
if (abcCode)
{
abcQueryRange.value(queryValue(abcCode));
}
super();

}

The query filtration part is done, you now need to fetch the value of “abcCode” from the caller. For this you need to grab the values from argument passed by the caller in the “init” method form.

Step 4

public void init()
{
if (element.args().record())
{
if (element.args().record().TableId == tablenum(x))
{
abcCode
= X::findRecId(element.args().record().RecId).abcCode;
}
}
super();

}

Import Bank Statement in AX 2012 through a CSV file

Import Bank Statement – CSV Format (AX 2012) Advance Bank Reconciliation Statement

Hello,
Today I will quickly show you how to import a Bank Statement (CSV format) in AX 2012. I am not at all good in writing so, will keep the post short and sweet.

How is it going to work?

We will upload a csv file have three fields date, amount and description to an inbound service. This service will convert the csv to xml file using manage transforms and then store back the data to AX.
4/06/2014,1921.46,test desc1
4/06/2014,-1238.49,test desc2
4/06/2014,-1124.2,test desc3
4/06/2014,-1077.46,test desc4

Environment:
1. Dynamic AX 2012 R2
2. Visual Studio

Check for Bankstatement Service and its Namespace

To start with please check if you have Bankstmt service available inside your AX. To do that goto AOT/Forms/AifService. Open this form and you will see list of services scroll down to BankStmtService and check for namespace.

If you find your namespace to be blank which was in my case then, you will have to manually add a namespace before we can proceed.
To add a namespace go back to AOT/Services scroll down to find BankStmtService. You can enter the namespace”http://schemas.microsoft.com/dynamics/2008/01/services” inside the properties of the BankStmt service. You will also have to refresh you service to make sure namespace is exposed.
Go back to AOT/Forms/AifService ->BankStmtService click on refresh at the top. This will take a while in some cases but you will find your namespace there now.

Create Transformation Library

In Order to create a transformation library, we need to implement an interface found in Microsoft.Dynamics.IntegrationFramework.This DLL can be found in the directory: C:\Program Files\Microsoft Dynamics AX\60\Client\Bin\ 

To start with create a Class Library type Visual studio project. Add a reference to the Microsoft.Dynamics.IntegrationFramework.Dll using the link above, and create a new class which implements the interface ITransform found in Microsoft.Dynamics.IntegrationFramework.Transform.ITransform

Then create a method which implements the method Transform. This method takes in 3 parameters
1. input (System.IO.Stream) : This is the input stream which is be the file itself
2. output (System.IO.Stream marked as out): This is the output stream that will be returned back to AX. We need to populate this stream
3. configuration (string): This is a custom configuration string that can be added to the port and can be used by the transformation. in this case we will not be using it.

So now we need to add code to read the data from the CSV file, which will be sent in the input stream as a parameter.
The CSV file we are going to add has 3 fields – Date, Amount, Description

The code should look like this, Its just reading a file and splitting the line contents.

We now need to compile the project and load the resulting DLL into AX.

More information about the Transformation can be found at: Walkthrough: Creating a .NET Assembly Transform [AX 2012]

Creating an Inbound port and loading the Transformation library

Now we will create a inbound port which will consume this transformation library dll. Go to AX client, then system administrator/setup/Services and Application Integration Framework/Inbound ports.

Click on New, give  the port a  name and description. Select Adapter has File System adapter, point it to a folder under URI. Under processing options, tick on transform all request and click on Inbound transforms.

Now click on manage transforms, click new give it a name and description, select type as .net assembly then hit Load to upload your Dll which you have created above. Once this is done, hit close and on the inbound transform form click new and select the newly created manage transform under Transform name. Hit close and on the inbound port under troubleshooting fast tab selectlogging mode as All document versions and tick Include exceptions in fault. That’s it we are done, activate the port.

Configuring Advance Bank Reconciliation Statement

Now, we need to configure Bank accounts to accept external statement. Go to Cash & bank management in your ax client. Under common, open bank accounts. Select the account which you want to configure for import and click edit. Under Reconciliation fast tab, tick Advanced bank Reconciliation. Under statement format, right click and select view details. This will open up Bank statement type form. Click on new and give statement format a name, select the inbound port which you have created above under inbound port then select the checkbox for xml file and mention the file type as csv.

Testing

That’s it we are done now, time to test our hard work. Go back to Cash and Bank Management in ax client, select Bank statements and then click on Import Statement. Select Bank Account which you had marked as advance bank reconciliation above, under statement format select csv as statement format. Browse File folder field to the folder location of your file. Under select file, browse through the file that you want to import and click OK. You will see a info box confirming your import.
Good luck 🙂

Whenever you update your class you will have to redeploy the dll to ax. Please click the link for more information.