Quantcast
Channel: Microsoft Dynamics 365 Community
Viewing all articles
Browse latest Browse all 17314

Microsoft Dynamics AX 2012 Custom Web Services Wizard

$
0
0
Microsoft Dynamics AX 2012 Custom Web Services Wizard
 
Purpose: The purpose of this document is to illustrate how to generate Data Contract and Service Contract classes for Custom Web Services in Microsoft Dynamics AX 2012.
 
Challenge: In order to use Custom Web Services in Microsoft Dynamics AX 2012 you have to introduce appropriate Data Contract and Service Contract classes. Often times Data Contract classes will be created based on existing data model (for example, tables or views) as is which makes it possible to automate this process.           
 
Solution: In order to generate Data Contract and Service Contract classes for Custom Web Services in Microsoft Dynamics AX 2012 based on existing data model as is I created a simple X++ job automating this process. 
 
Walkthrough
 
Often times I create Custom Web Services in Microsoft Dynamics AX 2012 that’s why I decided to automate some of the routine work I usually do when creating Data Contracts and Service Contracts
 
Let’s discuss Data Contracts first. When I create a new Data Contract based on existing data model as is, say, we take CustGroup table as an example I’ll have to create a class and a number of methods to expose different data elements/fields. More specifically for each data element/field I want to expose I’d create a separate method with DataMemberAttribute attribute which is used to define serialization of the accessor method as a data member
 
 
In case you have just a few fields to expose it will not take a lot of time, however if you have more than just a few fields the process may be tedious. Here is how we can generate Data Contract class for our example in a flash
 
Source code
 
staticvoid DataContract(Args _args)
{
    ClassBuild classBuild;
 
    str        header;
    str        vars;
    str        newClassName = "AlexDataContract";
 
    DictTable  dictTable;
    DictField  dictField;
    DictType   dictType;
 
    TableId    tableId;
    FieldId    fieldId;
    ExtendedTypeId typeId;
 
    str        tableName = "CustGroup";
    str        fieldName;
    str        typeName;
 
    int        i;
    ;
 
    header = 'public class ' + newClassName;
 
    classBuild = new ClassBuild(newClassName);
   
    tableId = tableName2id(tableName);
    dictTable = new DictTable(tableId);
   
    if (dictTable)
    {   
        for (i=1; i<= dictTable.fieldCnt(); i++)
        {
            fieldId = dictTable.fieldCnt2Id(i);
            dictField = new DictField(tableId, fieldId);
           
            if (dictField)
            {
                typeId = dictField.typeId();
               
                if (typeId != 0)
                {
                    dictType = new DictType(typeId);
        
                    if (dictType)
                    {
                        if (!dictField.isSystem())
                        {
                            fieldName = strFmt("%1", dictField.name());           
                            typeName = strFmt("%1", dictType.name());
           
                            classBuild.addMethod(fieldName, '[DataMemberAttribute]' + '\n' +
                            'public ' + typeName + ' ' + fieldName + '(' + typeName + ' _' + fieldName + ' = ' + fieldName + ')' + '\n' +
                            '{' + '\n' +
                            '\t' + fieldName + ' = _' + fieldName + ';' + '\n' +
                            '\t' + 'return ' + fieldName + ';' + '\n' +
                            '}');
                           
                            vars += '\t' + typeName + "\t" + fieldName + ';' + '\n';
                        }
                    }
                }
            }
        }
    }
   
    classBuild.addMethod('classdeclaration', '[DataContractAttribute]' + '\n' + header + '\n{\n' + vars + '}\n');
   
    classBuild.classNode().AOTcompile(1);
}
 
Here’s the result
 
 
Example
 
[DataContractAttribute]
publicclass AlexDataContract
{
         PlTaxPeriodPaymentCode    TaxPeriodPaymentCode_PL;
         DimensionDefault DefaultDimension;
         BankCustPaymIdRecId       BankCustPaymIdTable;
         CustVendTaxGroup TaxGroupId;
         PaymTermId       PaymTermId;
         ClearingPeriod   ClearingPeriod;
         Description      Name;
         CustGroupId      CustGroup;
}
 
 
[DataMemberAttribute]
public BankCustPaymIdRecId BankCustPaymIdTable(BankCustPaymIdRecId _BankCustPaymIdTable = BankCustPaymIdTable)
{
         BankCustPaymIdTable = _BankCustPaymIdTable;
         return BankCustPaymIdTable;
}
[DataMemberAttribute]
public ClearingPeriod ClearingPeriod(ClearingPeriod _ClearingPeriod = ClearingPeriod)
{
         ClearingPeriod = _ClearingPeriod;
         return ClearingPeriod;
}
[DataMemberAttribute]
public CustGroupId CustGroup(CustGroupId _CustGroup = CustGroup)
{
         CustGroup = _CustGroup;
         return CustGroup;
}
[DataMemberAttribute]
public DimensionDefault DefaultDimension(DimensionDefault _DefaultDimension = DefaultDimension)
{
         DefaultDimension = _DefaultDimension;
         return DefaultDimension;
}
[DataMemberAttribute]
public Description Name(Description _Name = Name)
{
         Name = _Name;
         return Name;
}
[DataMemberAttribute]
public PaymTermId PaymTermId(PaymTermId _PaymTermId = PaymTermId)
{
         PaymTermId = _PaymTermId;
         return PaymTermId;
}
[DataMemberAttribute]
public CustVendTaxGroup TaxGroupId(CustVendTaxGroup _TaxGroupId = TaxGroupId)
{
         TaxGroupId = _TaxGroupId;
         return TaxGroupId;
}
[DataMemberAttribute]
public PlTaxPeriodPaymentCode TaxPeriodPaymentCode_PL(PlTaxPeriodPaymentCode _TaxPeriodPaymentCode_PL = TaxPeriodPaymentCode_PL)
{
         TaxPeriodPaymentCode_PL = _TaxPeriodPaymentCode_PL;
         return TaxPeriodPaymentCode_PL;
}
 
Please note that each accessor method return type is based on actual EDT used for the field
 
Speaking about Service Contracts what I did I generated a backbone of Service Contract class with empty action methods, however some more automation can be provided for Service Contract class too as necessary 
 
Source code
 
staticvoid ServiceContract(Args _args)
{
    ClassBuild classBuild;
 
    str header;
    str newClassName = "AlexServiceContract";
    ;
 
    header = 'public class '+ newClassName;
 
    classBuild = new ClassBuild(newClassName);
 
    classBuild.addMethod('classdeclaration', header + '\n{\n}\n');
 
    classBuild.addMethod('createEntity', '[SysEntryPointAttribute(true)]' + '\n' + 'public void createEntity()' + '\n{\n}\n');
    classBuild.addMethod('readEntity', '[SysEntryPointAttribute(true)]' + '\n' + 'public void readEntity()' + '\n{\n}\n');
    classBuild.addMethod('updateEntity', '[SysEntryPointAttribute(true)]' + '\n' + 'public void updateEntity()' + '\n{\n}\n');
    classBuild.addMethod('deleteEntity', '[SysEntryPointAttribute(true)]' + '\n' + 'public void deleteEntity()' + '\n{\n}\n');
 
    classBuild.classNode().AOTcompile(1);
}
 
As the result I will have Service Contract class generated with placeholder methods which can be then filled with X++ code
 
 
Example
 
publicclass AlexServiceContract
{
}
[SysEntryPointAttribute(true)]
publicvoid createEntity()
{
}
[SysEntryPointAttribute(true)]
publicvoid deleteEntity()
{
}
[SysEntryPointAttribute(true)]
publicvoid readEntity()
{
}
[SysEntryPointAttribute(true)]
publicvoid updateEntity()
{
}
 
In case you just need to expose some read-only data this approach can also be applied for views. Using views you can create a representation of an entity which consists of multiple tables 
 
For the sake of simplicity in this walkthrough I’ll just wrap CustGroup table with a view and generate Data Contract and Service Contract classes for it, in fact your view may consist of multiple tables as necessary
 
 
Source code
 
staticvoid DataContract(Args _args)
{
    ClassBuild classBuild;
 
    str        header;
    str        vars;
    str        newClassName = "AlexDataContract";
 
    DictTable  dictTable;
    DictField  dictField;
    DictType   dictType;
 
    TableId    tableId;
    FieldId    fieldId;
    ExtendedTypeId typeId;
 
    str        tableName = "AlexCustGroup";
    str        fieldName;
    str        typeName;
 
    int        i;
    ;
 
The result will be identical
 
 
Now we could also implement readEntity method on Service Contract which returns entity details  
 
Please note that staging tables can also be used to represent entity which consists of multiple tables much like this is done in Microsoft Dynamics AX 2012 DIXF (Data Import Export Framework). Or you might want to generate distinct Data Contracts for distinct tables, say, header and lines example
 
Please find more info about how to create Custom Web Services in Microsoft Dynamics AX 2012 here: http://technet.microsoft.com/en-us/library/hh509052.aspx
 
For more practical examples of using Custom Web Services in Microsoft Dynamics AX 2012 you may also visit my another blog here: http://ax2012aifintegration.blogspot.com/2013/11/microsoft-dynamics-ax-2012-wcf-custom.html
 
Summary: This document describes how to generate Data Contract and Service Contract classes for Custom Web Services in Microsoft Dynamics AX 2012.
 
Tags: Microsoft Dynamics AX 2012, Custom Web Services, Data Contract, Service Contract, X++.
 
Note: This document is intended for information purposes only, presented as it is with no warranties from the author. This document may be updated with more content to better outline the issues and describe the solutions.
 
Author:Alex Anikiev, PhD, MCP 

Viewing all articles
Browse latest Browse all 17314

Trending Articles