Data Contracts and Custom Services [AX 2012]

In my previous post, I had explained the procedure to create custom services. The post contained usage of Basic types for exchanging data. In this post, I will explain the way to use complex data types and exchanging data where we need to provide or receive more than one data field as request/response.

To accomplish this, Dynamics AX provides concept of Data Contracts. Data Contracts are used to specify the input and return parameters for Services. Microsoft Dynamics AX utilizes the WCF data contracts to use .Net and X++ data types (both basic and complex). The serialization and deserialization of Data Contracts is handled by WCF framework itself.

What we as developers need to ensure is that we specify proper attributes to the contract classes and methods to ensure that proper serialization and deserialization happens for our contract classes.

Serialization Attributes

  • DataContractAttribute – This attribute specifies that the class should be serialized and can be used as a data contract. It is applied at the class level (specified on classDeclaration).

  • DataMemberAttribute – This attribute specifies the serializable methods in the data contract class. The attribute can be applied to public and instance methods, as long as the method uses a get/set pattern that contains one optional parameter (methods similar to the famous ‘parm’ methods of AX Business Classes).

Procedure to create data contract classes

Described below is the procedure to create and use the data contract classes. Note that you will need to first finish the task specified in my previous blog to create custom service to carry on with this procedure.

  • In AOT –> Classes node, right click and create new class
  • Name it as SamCustomServiceContract
  • In method classDeclaration, before the method signature, add the attribute [DataContractAttribute]

/// <summary>

/// Data Contract class for SamCustomServiceTest custom service demo class

/// </summary>

/// <remarks>

/// This is the Data Contract class for the custom service demo class SamCustomServiceTest

/// </remarks>

[DataContractAttribute]

class SamCustomServiceContract

{

    CustName    custName;

    CustGroupId custGroupId;

    LanguageId  defaultLanguage;

}

 

  • Add three serializable parm methods to the class to get/set customer name, customer group and default language

parmCustGroupId

/// <summary>

/// Gets or sets the value of the datacontract parameter CustGroupId.

/// </summary>

/// <param name=”_custGroupId”>

/// The new value of the datacontract parameter CustGroupId; optional.

/// </param>

/// <returns>

///  The current value of datacontract parameter CustGroupId

/// </returns>

[

    DataMemberAttribute(‘CustGroupId’)

]

public CustGroupId parmCustGroupId(CustGroupId _custGroupId = custGroupId)

{

    custGroupId = _custGroupId;

 

    return custGroupId;

}

 

parmCustName

 

/// <summary>

/// Gets or sets the value of the datacontract parameter CustName.

/// </summary>

/// <param name=”_custName”>

/// The new value of the datacontract parameter CustName; optional.

/// </param>

/// <returns>

///  The current value of datacontract parameter CustName

/// </returns>

[

    DataMemberAttribute(‘CustName’)

]

public CustName parmCustName(CustName _custName = custName)

{

    custName = _custName;

 

    return custName;

}

 

parmDefaultLangauge

/// <summary>

/// Gets or sets the value of the datacontract parameter DefaultLanguage.

/// </summary>

/// <param name=”_defaultLanguage”>

/// The new value of the datacontract parameter DefaultLanguage; optional.

/// </param>

/// <returns>

///  The current value of datacontract parameter DefaultLanguage

/// </returns>

[

    DataMemberAttribute(‘DefaultLanguage’)

]

public LanguageId parmDefaultLanguage(LanguageId _defaultLanguage = defaultLanguage)

{

    defaultLanguage = _defaultLanguage;

 

    return defaultLanguage;

}

 

The Contract Class is ready for utilization. Now let us go ahead and add a method to our custom service class to utilize this contract class.

For this, select our previously created service class, SamCustomServiceTest and add following method to the class

/// <summary>

/// Gets a list of customer ids from the specified company

/// </summary>

/// <param name=”_custList”>

/// The list of customer ids; Mandatory

/// </param>

/// <returns>

///  List of customer information

/// </returns>

/// <remarks>

/// AifCollectionTypeAttribute is used to define strongly typed containers for data

/// </remarks>

[SysEntryPointAttribute(true),

 AifCollectionTypeAttribute(‘return’, Types::Class, classStr(SamCustomServiceContract)),

 AifCollectionTypeAttribute(‘_custList’, Types::String)]

public List retrieveCustomerInfo(List _custList)

{

    SamCustomServiceContract    dataContract;

    ListEnumerator  listEnum = _custList.getEnumerator();

    List            resultSet = new List(Types::Class);

    CustTable       custTable;

 

    while (listEnum.moveNext())

    {

        select firstOnly custTable

            where custTable.AccountNum == listEnum.current();

 

        dataContract = new SamCustomServiceContract();

 

        if (custTable)

        {

            dataContract.parmCustGroupId(custTable.CustGroup);

            dataContract.parmCustName(custTable.name());

            dataContract.parmDefaultLanguage(custTable.languageId());

        }

 

        resultSet.addEnd(dataContract);

    }

 

    return resultSet;

}

 

Note: The return type is class and we have to provide the name of the serializable class that will be used for returning data. The return type is specified by AifCollectionTypeAttribute attribute.

  • Now that the service is ready, select the service group and deploy it again
  • Now open the visual studio and the project we created earlier to modify it and use the newly created service operation
  • In Visual Studio, under Service Reference node, select our custom service, right click and select “Update Service Reference”

image

  • Open the existing form and add a “List view” type control and a button. The List view type control should have View property set to “Detail” and 4 columns should be added using the “Columns” collection property as shown below

image

  • Now double click on “Get Customer Info” button and add following code

private void button4_Click(object sender, EventArgs e)

{

    string[] strItem = null;

    int i = 0;

    SamCustomAXService.CallContext callContext = new SamCustomAXService.CallContext();

    SamCustomAXService.SamCustomServiceClient servClient = new SamCustomAXService.SamCustomServiceClient();

 

    strItem = new string[listBox1.SelectedItems.Count];

 

    //Get selected customer ids and prepare a string array

    foreach (Object selecteditem in listBox1.SelectedItems)

    {

        string item = selecteditem as string;

        strItem[i++] = item;

    }

 

    //Use the Data Contract array to get the customer information

    SamCustomAXService.SamCustomServiceContract[] custInfo = servClient.retrieveCustomerInfo(callContext, strItem);

 

    listView1.Items.Clear();

    i = 0;

    foreach (SamCustomAXService.SamCustomServiceContract custDet in custInfo)

    {

 

        ListViewItem item = listView1.Items.Add(strItem[i++]);

        item.SubItems.Add(custDet.CustName);

        item.SubItems.Add(custDet.CustGroupId);

        item.SubItems.Add(custDet.DefaultLanguage);

    }

}

 

Now save the package, build it and run, first click on button “Get Customers”, then select some customers and click on button “Get Customer Info” this is what you will see

image

This concludes the post, I will keep on adding more topics on custom services as and when I try them out.

12 thoughts on “Data Contracts and Custom Services [AX 2012]

  1. Hi Sumit,
    Waht ever you given that is help full but what my doubt is how we can create my own schema class for contract handaling in ax 2012 please can you describe that also in ax 2012 in your next post

    1. Sure. But that may not be anytime soon. It will depend on the time I can find for writing the articles.

      Thanks for reading my blogs and suggestions for topics 🙂

  2. Hi, Sumit.

    I think one step is missing:
    After create the ”retrieveCustomerInfo” method, and before deploy the service group, you should add the operator to the service.

    Many many many thanks for the post. It’s very useful.

  3. Hi Sumit,

    Thanks for this article. I have one question. XML generated by AX with this service(System Administration – > Periodic – > Services and AIF – > History- > Document Log -> View XML). Can we change the format of XML ? In my case all entities are coming with Alias A:, B: etc depends on level. I don’t want these aliases and also SenderId is not coming, how we can control over format of XMl ?

    1. The format of XML that is accepted by Services and AIF is pretty rigid. If you want to use standard AIF documents then the incoming XML needs to be in the format defined by each AIF schema of a specific document. Having said that it is not necessary and neither it is expected for other systems to generate the XML in same format. You can write the XSLT files or .Net assemblies to do the XML transformation of the incoming XML to map the format that is accepted by AIF. You can then use this transformation/assembly in Inbound Pipelines. Also regarding the values, you can use Value mapping or External codes feature to convert the values from A to B

  4. Thanks much Sumit, however my concern is more about outbound XML than incoming. I have created similar Data Contract and Service class for product. As far as consuming this service from .Net there is no issue as we are just exposing Data contract Parm methods. But AX also generates XML as a response which might be consume at web service(not sure). But my client is looking at XML from System Administration – > Periodic – > Services and AIF – > History- > Document Log -> View XML. But he has concern over format of XML .. mainly two things 1. Sender id Tag is missing 2. For every element Aliases are coming as A: or B:. For example ‘1001’ , i want to remove B: from this element. Is there any way to change within AX ?

  5. Hi Sumit,

    It was very nice post and helpful…

    How to take complex parameters from the input and process it through datacontract class and service class and responds through web service…

    your reply would be highly appreciated…….

    Thanks,
    Kumar.

  6. Hi Sumit,
    Can you please explain, how to consume, Axapta data contract classin in Visual Studio to send the XML info in the AIF inbound service, for example i have the XML file, i want use data contract class in Visual studio to de serialize the XML and sent to the in bound service.

  7. Hi, nice post. Thanks for that.
    I have a requirement where I need to get xml orders from an external system called “Channel Adviser”. It’s a software which tracks all amazon, ebay and other e-commerce websites for my business and creates an xml file. I need to “ideally” use AIF or services to get these xml orders from that external system and create their respective sales orders in AX 2012.
    I have never used AIF before, so is there any procedure that you think is the right approach for this requirement?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s