Test AIF Services with X++ job (create, update and delete)

In order to test document services we need to do many steps from configuring AIF until the setup and development in visual studio. This post provide an easy tool to test AIF services (crea

In order to test document services we need to do many steps from configuring AIF until the setup and development in visual studio. This post provide an easy tool to test AIF services (create, update and delete) with a X++ job in Ax 2012. In this example we are going to test operation service functions of the document service created in my previous post ( CRUD Operations with AIF Document Services in Visual Studio) . We are doing this test in Dynamics Ax and there is no need for AIF/VS setup or have XML files available.

As we create a Document service with the AIF Document Service Wizard,

In de Wizard we choose the yellow marked service operations:

When complete the wizard, the system will generate a private project with objects in the AOT .We see that system generated 5 different classes with have each it’s own extension:

first class has an extension to AxInternalBase class. With the AxInternal base we can store objects or records.

We see a second class generated with an ‘AxdBase’ extension. Classes extend the AxdBase class are the document classes. They represent business documents. An example of a business document could be an inventory journal or a sales/purch order. A document class also handles the generation of XML Schema Definition (XSD), which defined the document structure and business rules. In my next posts I will write more about XSD.

The third class has an extension to AIFDocumentService. Actually this class implements the service operations that we have defined in the Service Operation section of the wizard.

The fourth class has an extension to the AIFDocument class, which provide the data for the service class.

The last generated class has an extension  to the AfStringlyTypeDataContainer class. Also this class provide data to the service class.

In this example we gonna test the create, update and delete service in a job, without XML file and without AIF setup. In order to do this we use the classes extended to the  AIFDocumentService, AIFDocument and the AfStringlyTypeDataContainer.

Apart from that, we need for the both update and delete operations also the AifEntityKeyList. In order to use the AifEntityKeyList list we also need the AifEntityKey. Example how to get a correct AifEntityKetList with X++:

Regarding the AIFDocument class. For the update operations a hashcode is mandatory. See the code to generate the hashcode:

With the variable ‘entityAction’ can be switched between the operations Create, Update and Delete.

We give the parameters in the class which is extended to ‘ AfStringlyTypeDataContainer’, via the class which is extended to AIFDocument.

Appendix: full code of the job:

static void testJobAIFDocumentServices(Args _args)
{
    #define.CourseId("AX7-DEVI")
    #define.CourseName("AX7 Introduction DevelopmentI")
    #define.Trainer("van Kessel")

    FOXCourseQueryService           service;        
		// Service class (extends with AifDocumentService)
    FOXCourseDocument               document;       
		// Document object (extends with AifDocument)
    FOXCourseDocument_FoxCourse     dataObject;     
		// Data object (extends with                                                                                        AifStronglyTypedDataContainer)    
    String30                        id;
    Map                             map;
    AifEntityKey                    key             = new AifEntityKey();
    AifEntityKeyList                entityKeyList   = new AifEntityKeyList();
    //Choose the transactiontype

    AxdEntityAction                 entityAction =   
					AxdEntityAction::update;

    str getHashCode(String30  _courseId)
    {
        //Hashcode is mandatory for updating
        AxdBaseRecordInfo       recordInfo;
        FOXCourse               foxCourseLoc;
        str                     documentHash;
        Map                     dataSourceMap
                            = new Map(Types::Integer,Types::Integer);
    
        select firstOnly name, trainer from foxCourseLoc
            where foxCourseLoc.Id ==  _courseId;

        recordInfo                  
			= AxdBaseRecordInfo::newCommon(foxCourseLoc,
                                                                 1 ,
                                                      dataSourceMap);
        documentHash                = recordInfo.getRecordHash();

        return documentHash;
    }

    void getDocumentData()
    {
        document = new FOXCourseDocument();
        document.createFoxCourse();

        dataObject = document.parmFoxCourse().addNew();

        if (entityAction == AxdEntityAction::update)
        {
            //Hashcode is mandatory by update
            dataObject.parm_DocumentHash(getHashCode(#CourseId));
        }

        //Key Id should also given for update
        //In that case should the given key the same as he orig key
        // (see validation rule in AxdBase/checkFieldsForUpdate)

        dataObject.parmId(#CourseId);
        dataObject.parmName(#CourseName);
        dataObject.parmTrainer(#Trainer);
    }
   
    //Instantiate the service
    service = FOXCourseQueryService::construct();
    //Document

    if (entityAction == AxdEntityAction::update 
	|| entityAction == AxdEntityAction::create)
    {
        getDocumentData();
    }

    // Compose the map with the keyfield
    map = new Map(Types::Integer, Types::Container);
    map.insert(fieldnum(FOXCourse, Id), [#CourseId]);
    // Compose the keyfield
    key.parmTableId(tablenum(FOXCourse));
    key.parmKeyDataMap(map);
    // Compose the entity key list   
    entityKeyList.addEntityKey(key);
 
    // run the service
    switch (entityAction)
    {
        case AxdEntityAction::create :

                service.create(document);

            break;

        case AxdEntityAction::update :

                service.update(entityKeyList, document);

            break;

        case  AxdEntityAction::delete :

                service.delete(entityKeyList);

            break;
    }

    id  = entityKeyList.getEntityKey(1).parmKeyDataMap().lookup(fieldnum(FOXCourse, Id));
    info(strfmt("Course %1 is %2d", id, entityAction));
}

Code of job