Microsoft Dynamics 365 for Operations – How Packages and Models live in Visual Studio
In continuation of my previous post on few major technical changes in the world of AX 7, this post is all about to understand the core components of AX 7 development before we jump into AX development IDE in visual studio. Yes, we will write X++ code into Visual Studio by using four components. There are 4 main components to understand in Visual Studio include Elements, Models, Projects and Packages. To explore more let’s have a look at a screenshot of the Application Explorer. Within it, there is an AOT node. Model(s) and Packages(s) in Visual Studio environment I am gonna dig dipper into what Model and Package mean? Model: Model is a group of elements that represents the particular solution (Tables, Forms, and Classes e.t.c) The definition of the Model is similar to what it was in AX 2012 (AX 2012 Models) Model is a design time concept. For example A Fleet Management Model, A Project Account Model A Model may contains multiple Visual Studio projects. However, a project many only belong to one model All of the sub-nodes below the AOT node are different models, this is call Model View Package: A Package is a more of a compilation unit and distribution unit to move binaries and any other runtime artefacts that your model need between environments during the development ALM process. For example; moving them from the development box to the Cloud to run. A Package typically is one or more Packages typically packages into one we called deployment package and this is the unit that you use to move code to Cloud. A Package is a deployment unit that may contain one ore more models. In addition to elements, it includes more metadata, which is a description data that defines the properties and behaviour of the model. A Package can be exported into a file which can then be deployed into a staging or production environment. Model in AX 2012 and in AX 7Model concept in AX 7 is quite similar to what it was in AX 2012. These are the source code so ISV distributing their solutions to partners or to customers are typically giving the models, they don’t provide Packages. They provide models that can be installed onto your box, customize them and the move them into your Cloud environment. Package in AX 2012 and in AX 7 In the AX 2012 world, Package is closer to what we used to call the model store to what we used to call the model files. Because you know they are pre-compiled things that you can deploy to a production or to UAT environment. Visual Studio Project and Elements I am gonna dig dipper into what Project and Element mean? Visual Studio Projects Recommended way of development is to create Visual Studio project for all changes and the project always belongs to model, you can think of them is a subset of your model. Why do we have a different concept for model and project? The only reason we have two concepts of a model and a project is, typically AX 7 models are very large and its not a good practice to compile entire model for a simple code change activities during your development. Project always belongs to a particular model and is basically a subset of elements that belongs a model. One or more model can constitute a package, typically every package has one model. The reason sometimes we have one or more models in particular package when you customize during overlaying of source code. Elements Elements are AOT objects, for example; Base Enums, Extended Data Types, Tables, Classes, Forms, and Menu items and a lot more. Stay tuned! I will be posting more on how we can use these four components in real development. Happy Dax!ng
How to: Generate number sequence for new developed module in AX 2012
In this post I am going to create a number sequence for newly developed module in AX 2012. 1. Add a new element in NumberSeqModule baseenum with your new module name 2. Create a new Class NumberSequenceModuleModuleName extends NumberSequenceModule 3. Override loadModule method by adding the parameters of the sequence NumberSeqDatatype datatype = NumberSeqDatatype::construct(); //Message ID: MessageID is a new EDT of string type datatype.parmDatatypeId(extendedtypenum(MessageID)); datatype.parmReferenceHelp(literalstr(“MessageId”)); datatype.parmWizardIsManual(NoYes::No); datatype.parmWizardIsChangeDownAllowed(NoYes::No); datatype.parmWizardIsChangeUpAllowed(NoYes::No); datatype.parmSortField(2); datatype.addParameterType(NumberSeqParameterType::DataArea, true, false); this.create(datatype); 4. Override numberSeqModule method public NumberSeqModule numberSeqModule() { return NumberSeqModule::NewModule; } 5. Create new job to load number sequence static void MessageIDNumSeqLoad(Args _args) { NumberSeqApplicationModule::loadAll(); } 6. Go to Organisation Administration | Common Forms | Number sequences | Number Sequences | Generate and follow the wizard to end to generate number sequence for new module.
AX 2012 – sysOperation Framework – Use controller class to open dialog from AX form
In my previous post on sysOperation framework Example I described how the sysOperation framework can be used for the batch functionality in contrast to RunBaseBatch framework. In this post I will explain how you can use sysOperation Framework classes to open a dialog from a AX form using contract and controller classes and then run logic in Service class. In this example I added a new menu item “Example” on projProjectsListPage form which will call controller class. This example is create project transactions using service calls at the end. First we need to create a contract class which holds parameters (dialog fields value or user input). To keep it simple I only added two parameters ProjId (Project Id) and ProjContractId (Project Contract Id). That’s the model part of MVC pattern and view part is automatically created by using these data member attributes. [DataContractAttribute] class FF_ExampleContract { ProjId projId; ProjInvoiceProjId projContractId; } [DataMemberAttribute, SysOperationLabelAttribute(literalStr(“Selected Project Id”)), SysOperationHelpTextAttribute(literalStr(“Selected Project Id from projects”)), SysOperationDisplayOrderAttribute(‘1’) ] public ProjId parmProjId(ProjId _projId = projId) { projId = _projId; return projId; } [DataMemberAttribute, SysOperationLabelAttribute(literalStr(“Selected Project contract Id”)), SysOperationHelpTextAttribute(literalStr(“Selected Project Contract Id from projects”)), SysOperationDisplayOrderAttribute(‘2′) ] public ProjInvoiceProjId parmProjContractId(ProjInvoiceProjId _projContractId = projContractId) { projContractId = _projContractId; return projContractId; } Let’s move to controller part of sysOperation framework and create a new controller class. For this example I don’t need to have batch tab on dialog, so I set return value to FALSE in canGoBatch() method. class FF_ExampleController extends SysOperationServiceController { Common callerRecord; } public static void main(Args _args) { FF_ExampleController controller; controller = FF_ExampleController::newFromArgs(_args); controller.parmShowDialog(true); controller.initFromCaller(); controller.startOperation(); controller.refreshCallerRecord(); } public static FF_ExampleController newFromArgs(Args _args) { FF_ExampleController controller; IdentifierName className; IdentifierName methodName; SysOperationExecutionMode executionMode; [className, methodName, executionMode] = SysOperationServiceController::parseServiceInfo(_args); if (_args.record()) { executionMode = SysOperationExecutionMode::Synchronous; } controller = new FF_ExampleController(className, methodName, executionMode); controller.parmArgs(_args); controller.parmCallerRecord(_args.record()); return controller; } public LabelType parmDialogCaption(LabelType _dialogCaption = “”) { LabelType caption; // This appears as the window name caption = “Create project transaction”; return caption; } protected void new( IdentifierName _className = classStr(FF_ExampleService), IdentifierName _methodName = methodStr(FF_ExampleService, example), SysOperationExecutionMode _executionMode = SysOperationExecutionMode::ReliableAsynchronous ) { super(_className, _methodName, _executionMode); } private void initFromCaller() { #define.dataContractKey(‘_contract’) FF_ExampleContract contract; ProjTable projTable; contract = this.getDataContractObject(#dataContractKey) as FF_ExampleContract; switch (this.parmCallerRecord().TableId) { case tableNum(ProjTable) : projTable = this.parmCallerRecord() as ProjTable; contract.parmProjId(projTable.ProjId); contract.parmProjContractId(projTable.ProjInvoiceProjId); break; } } public boolean canGoBatch() { return false; } public Common parmCallerRecord( Common _callerRecord = callerRecord ) { callerRecord = _callerRecord; return callerRecord; } /// <summary> /// Refreshes the calling form data source. /// </summary> protected void refreshCallerRecord() { FormDataSource callerDataSource; if (this.parmCallerRecord() && this.parmCallerRecord().dataSource()) { callerDataSource = this.parmCallerRecord().dataSource(); callerDataSource.research(true); } } In the new method of controller class it is eventually calling service class method. We could create a method in controller class itself and refer that method into the new method of controller class to process business logic. This seems to be a lot for controller class, first to handle all parameters and then process business logic, recommended way is to separate the business logic in service class and another advantage of having service class is, these operations can also be used in web services (AIF) operations. That’s the separate topic and we will talk about it later… Let’s create new service class and add entry point method to process business logic. class FF_ExampleService { FF_ExampleContract contract; } [SysEntryPointAttribute] public void createProjectTransaction(FF_ExampleContract _contract) { ProjId projId; ProjInvoiceProjId projContractId; contract = _contract; projId = contract.parmProjId(); projContractId = contract.parmProjContractId(); /* …. create project transactions */ } Have we achieved what we aimed at start? We are almost there, just need to add a new action menu item and assign controller & service class to it. That’s it!!! run the menu item and see how it works… Click on Example menu item from Project list page, it opened a dialog with correct title ‘Create project transactions’ and with correct Project Id passed from calling form (ProProjectsListPage). Happy Dax!ng…